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:
parent
d807250030
commit
f369329874
15 changed files with 856 additions and 155 deletions
BIN
resources/bgm/stage6/boss_phase3.ogg
Normal file
BIN
resources/bgm/stage6/boss_phase3.ogg
Normal file
Binary file not shown.
4
resources/bgm/stage6boss_phase3.bgm
Normal file
4
resources/bgm/stage6boss_phase3.bgm
Normal 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
BIN
resources/sfx/noise1.ogg
Normal file
Binary file not shown.
|
@ -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
BIN
resources/sfx/warp.ogg
Normal file
Binary file not shown.
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
51
src/boss.c
51
src/boss.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue