Theory of Everything redesign (#103)

* WIP version of toe

* some toe adjustments

* toe first phase tweaks

* make the last phase less dense

* tweak the shifts in toe phase 1

* added some comments and adjusted the first phase, transition after higgs

* ToE bells and whistles

* fix invisible scythe

* fixed the single particle

* audio_mixer: revert audio_backend_sound_stop_loop to use Mix_HaltChannel

* ToE: some difficulty scaling and other tweaks

* made the boson colors use hsl

* Elly: ToE transition, some fixes

* Add ToE bgm (elly phase 3)
This commit is contained in:
Andrei Alexeyev 2018-01-08 18:56:46 +02:00 committed by GitHub
parent d807250030
commit f369329874
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 856 additions and 155 deletions

Binary file not shown.

View file

@ -0,0 +1,4 @@
title = Immutable Truth
artist = Tuck V
loop = res/bgm/stage6/boss_phase3.ogg
loop_point = 35.64

BIN
resources/sfx/noise1.ogg Normal file

Binary file not shown.

View file

@ -25,4 +25,6 @@ bomb_youmu_b = 100
bossdeath = 100
redirect = 70
boom = 70
powerup = 70
powerup = 70
noise1 = 70
warp = 80

BIN
resources/sfx/warp.ogg Normal file

Binary file not shown.

View file

@ -118,3 +118,11 @@ return vec2(
);
%%iku_cathode%%
return pos + cmul(t * a0, dir(a1.y * t));
%%elly_toe_fermion%%
return pos + a0*t;
%%elly_toe_photon%%
return pos+cmul(a0,vec2(t,a2.x*sin(t/a2.x)));
%%elly_toe_gluon%%
return pos+cmul(a0,vec2(t+a2.x*(0.6*(cos(3.*t/a2.x)-1.)),a2.x*sin(3.*t/a2.x)));
%%elly_toe_higgs%%
return pos+a0*(t+floor(t/a2.x)*a2.x);

View file

@ -376,8 +376,11 @@ bool audio_backend_sound_stop_loop(void *impl) {
return false;
MixerInternalSound *snd = (MixerInternalSound *)impl;
if(snd->loopchan == -1)
if(snd->loopchan == -1) {
return false;
}
Mix_HaltChannel(snd->loopchan);
return true;

View file

@ -117,8 +117,22 @@ static bool boss_should_skip_attack(Boss *boss, Attack *a) {
//
// (for example, the "Generic move" that might have been automatically added by
// boss_add_attack_from_info. this is what the a->info->type check is for.)
if(boss->failed_spells && (a->type == AT_ExtraSpell || (a->info && a->info->type == AT_ExtraSpell))) {
return true;
}
return boss->failed_spells && (a->type == AT_ExtraSpell || (a->info && a->info->type == AT_ExtraSpell));
// Immediates are handled in a special way by process_boss,
// but may be considered skipped/nonexistent for other purposes
if(a->type == AT_Immediate) {
return true;
}
// Skip zero-length spells. Zero-length AT_Move and AT_Normal attacks are ok.
if(ATTACK_IS_SPELL(a->type) && a->timeout <= 0) {
return true;
}
return false;
}
static Attack* boss_get_final_attack(Boss *boss) {
@ -264,7 +278,7 @@ void draw_boss(Boss *boss) {
if(ATTACK_IS_SPELL(boss->current->type))
spell_opening(boss, global.frames - boss->current->starttime);
if(boss->current->type != AT_Move) {
if(boss->current->type != AT_Move && boss->current->type != AT_Immediate) {
char buf[16];
float remaining = max(0, (boss->current->timeout - global.frames + boss->current->starttime)/(float)FPS);
Color textclr;
@ -298,7 +312,7 @@ void draw_boss(Boss *boss) {
if(boss_should_skip_attack(boss,&boss->attacks[nextspell]))
continue;
int t = boss->attacks[nextspell].type;
if(!attack_is_over(&boss->attacks[nextspell]) && t == AT_Spellcard)
if(ATTACK_IS_SPELL(t) && !attack_is_over(&boss->attacks[nextspell]))
break;
}
@ -308,7 +322,7 @@ void draw_boss(Boss *boss) {
continue;
int t = boss->attacks[prevspell].type;
if(attack_is_over(&boss->attacks[prevspell]) && t == AT_Spellcard)
if(ATTACK_IS_SPELL(t) && attack_is_over(&boss->attacks[prevspell]))
break;
maxhpspan += boss->attacks[prevspell].maxhp;
hpspan += boss->attacks[prevspell].hp;
@ -352,10 +366,15 @@ void draw_boss(Boss *boss) {
// remaining spells
glColor4f(1,1,1,0.7);
int x = 0;
for(int i = boss->acount-1; i > nextspell; i--)
if(boss->attacks[i].type == AT_Spellcard)
for(int x = 0, i = boss->acount-1; i > nextspell; i--) {
if(
ATTACK_IS_SPELL(boss->attacks[i].type) &&
(boss->attacks[i].type != AT_ExtraSpell) &&
!boss_should_skip_attack(boss, &boss->attacks[i])
) {
draw_texture_with_size(x += 22, 40, 20, 20, "star");
}
}
glColor3f(1,1,1);
}
@ -564,6 +583,11 @@ void process_boss(Boss **pboss) {
return;
}
if(boss->current->type == AT_Immediate) {
boss->current->finished = true;
boss->current->endtime = global.frames;
}
int time = global.frames - boss->current->starttime;
bool extra = boss->current->type == AT_ExtraSpell;
bool over = boss->current->finished && global.frames >= boss->current->endtime;
@ -693,6 +717,8 @@ void process_boss(Boss **pboss) {
stage_gameover();
}
log_debug("Current attack [%s] is over", boss->current->name);
for(;;) {
boss->current++;
@ -703,6 +729,17 @@ void process_boss(Boss **pboss) {
break;
}
if(boss->current->type == AT_Immediate) {
boss->current->starttime = global.frames;
boss->current->rule(boss, EVENT_BIRTH);
if(global.dialog) {
break;
}
continue;
}
if(boss_should_skip_attack(boss, boss->current)) {
continue;
}

View file

@ -36,7 +36,8 @@ typedef enum AttackType {
AT_Move,
AT_Spellcard,
AT_SurvivalSpell,
AT_ExtraSpell
AT_ExtraSpell,
AT_Immediate,
} AttackType;
#define ATTACK_IS_SPELL(a) ((a) == AT_Spellcard || (a) == AT_SurvivalSpell || (a) == AT_ExtraSpell)

View file

@ -99,7 +99,7 @@ static void projectile_size(Projectile *p, double *w, double *h) {
}
}
int projectile_prio_func(List *vproj) {
static int projectile_sizeprio_func(List *vproj) {
Projectile *proj = (Projectile*)vproj;
if(proj->priority_override) {
@ -110,7 +110,27 @@ int projectile_prio_func(List *vproj) {
}
List* proj_insert_sizeprio(List **dest, List *elem) {
return list_insert_at_priority(dest, elem, projectile_prio_func(elem), projectile_prio_func);
return list_insert_at_priority(dest, elem, projectile_sizeprio_func(elem), projectile_sizeprio_func);
}
static int projectile_colorprio_func(List *vproj) {
Projectile *p = (Projectile*)vproj;
Color c = p->color;
uint32_t c32 = 0;
float r, g, b, a;
// convert color to 32bit
parse_color(c, &r, &g, &b, &a);
c32 |= (((c & CLRMASK_R) >> CLR_R) & 0xFF) << 0;
c32 |= (((c & CLRMASK_G) >> CLR_G) & 0xFF) << 8;
c32 |= (((c & CLRMASK_B) >> CLR_B) & 0xFF) << 16;
return (int)c32;
}
List* proj_insert_colorprio(List **dest, List *elem) {
return list_insert_at_priority(dest, elem, projectile_colorprio_func(elem), projectile_colorprio_func);
// return list_push(dest, elem);
}
static Projectile* _create_projectile(ProjArgs *args) {
@ -665,11 +685,18 @@ void Fade(Projectile *p, int t) {
void ScaleFade(Projectile *p, int t) {
glPushMatrix();
apply_common_transforms(p, t);
glScalef(creal(p->args[1]), creal(p->args[1]), 1);
float a = (1.0 - t/creal(p->args[0])) * (1.0 - cimag(p->args[1]));
Color c = rgba(1, 1, 1, a);
double scale_min = creal(p->args[2]);
double scale_max = cimag(p->args[2]);
double timefactor = t / creal(p->args[0]);
double scale = scale_min * (1 - timefactor) + scale_max * timefactor;
double alpha = pow(1 - timefactor, 2);
// log_debug("%f %f %f %f", scale_min, scale_max, timefactor, scale);
Color c = multiply_colors(p->color, rgba(1, 1, 1, alpha));
glScalef(scale, scale, 1);
ProjDrawCore(p, c);
glPopMatrix();
}
@ -693,6 +720,17 @@ int timeout_linear(Projectile *p, int t) {
return 1;
}
int timeout_linear_fixangle(Projectile *p, int t) {
if(t >= creal(p->args[0]))
return ACTION_DESTROY;
if(t < 0)
return 1;
p->pos = p->pos0 + p->args[1]*t;
return 1;
}
void Petal(Projectile *p, int t) {
float x = creal(p->args[2]);
float y = cimag(p->args[2]);

View file

@ -170,6 +170,7 @@ void petal_explosion(int n, complex pos);
int timeout(Projectile *p, int t);
int timeout_linear(Projectile *p, int t);
int timeout_linear_fixangle(Projectile *p, int t);
int blast_timeout(Projectile *p, int t);
void Blast(Projectile *p, int t);
@ -177,3 +178,4 @@ void Blast(Projectile *p, int t);
void projectiles_preload(void);
List* proj_insert_sizeprio(List **dest, List *elem) __attribute__((hot));
List* proj_insert_colorprio(List **dest, List *elem);

View file

@ -31,6 +31,7 @@ static struct recolor_vars_s {
struct recolor_varcache A;
struct recolor_varcache O;
bool loaded;
int transfers;
} recolor_vars;
static inline void recolor_set_uniform(struct recolor_varcache *vc, Color clr) {
@ -40,6 +41,7 @@ static inline void recolor_set_uniform(struct recolor_varcache *vc, Color clr) {
parse_color_array(clr, clrarr);
glUniform4fv(vc->loc, 1, clrarr);
vc->prev = clr;
// log_debug("%i", ++recolor_vars.transfers);
}
}

View file

@ -48,7 +48,7 @@ struct stage6_spells_s stage6_spells = {
.final = {
.theory_of_everything = {{20, 21, 22, 23}, AT_SurvivalSpell, "Tower of Truth ~ Theory of Everything", 70, 40000,
elly_theory, elly_spellbg_modern, BOSS_DEFAULT_GO_POS}
elly_theory, elly_spellbg_modern, ELLY_TOE_TARGET_POS}
},
};
@ -251,6 +251,8 @@ static void stage6_preload(void) {
"stage6/towertop",
"stage6/towerwall",
"dialog/elly",
"part/stardust",
"part/myon",
NULL);
preload_resources(RES_SHADER, RESF_DEFAULT,
"tower_wall",
@ -264,6 +266,10 @@ static void stage6_preload(void) {
"towertop",
"skysphere",
NULL);
preload_resources(RES_SFX, RESF_DEFAULT | RESF_OPTIONAL,
"warp",
"noise1",
NULL);
}
static void stage6_end(void) {

File diff suppressed because it is too large Load diff

View file

@ -31,3 +31,6 @@ Boss* stage6_spawn_elly(complex pos);
void Scythe(Enemy *e, int t, bool render);
void scythe_common(Enemy *e, int t);
// #define ELLY_TOE_TARGET_POS (VIEWPORT_W/2+298.0*I)
#define ELLY_TOE_TARGET_POS (VIEWPORT_W/2+VIEWPORT_H/2*I)