Support extra spells in spell practice mode

Also fixed background lasers not rendering after @lasch0r's rebase
This commit is contained in:
Andrei "Akari" Alexeyev 2017-02-20 13:41:31 +02:00
parent cc00a8754e
commit 029c2597f6
7 changed files with 94 additions and 60 deletions

View file

@ -148,31 +148,31 @@ void boss_rule_extra(Boss *boss, float alpha) {
int cnt = 10 * max(1, alpha);
alpha = min(2, alpha);
int lt = 1;
if(alpha == 0) {
lt += 2;
alpha = 1 * frand();
}
int i; for(i = 0; i < cnt; ++i) {
float a = i*2*M_PI/cnt + global.frames / 100.0;
complex dir = cexp(I*(a+global.frames/50.0));
complex pos = boss->pos + dir * (100 + 50 * psin(alpha*global.frames/10.0+2*i)) * alpha;
complex vel = dir * 3;
float r, g, b;
float v = max(0, alpha - 1);
float psina = psin(a);
r = 1.0 - 0.5 * psina * v;
g = 0.5 + 0.2 * psina * (1-v);
b = 0.5 + 0.5 * psina * v;
create_particle2c("flare", pos, rgb(r, g, b), FadeAdd, timeout_linear, 15*lt, vel);
int d = 5;
if(!(global.frames % d))
if(!(global.frames % d))
create_particle3c((frand() < v*0.5 || lt > 1)? "stain" : "boss_shadow", pos, rgb(r, g, b), GrowFadeAdd, timeout_linear, 30*lt, vel * (1 - 2 * !(global.frames % (2*d))), 2.5);
}
}
@ -187,12 +187,12 @@ void boss_kill_projectiles(void) {
void process_boss(Boss **pboss) {
Boss *boss = *pboss;
if(boss->current) {
int time = global.frames - boss->current->starttime;
int extra = boss->current->type == AT_ExtraSpell;
int over = boss->current->finished && global.frames >= boss->current->endtime;
// TODO: mark uncaptured normal spells as failed too (for spell bonuses and player stats)
if(!boss->current->endtime || !extra)
@ -202,7 +202,7 @@ void process_boss(Boss **pboss) {
float base = 0.2;
float ampl = 0.2;
float s = sin(time / 90.0 + M_PI*1.2);
if(boss->current->endtime) {
float p = (boss->current->endtime - global.frames)/(float)ATTACK_END_DELAY_EXTRA;
float a = max((base + ampl * s) * p * 0.5, 5 * pow(1 - p, 3));
@ -228,7 +228,7 @@ void process_boss(Boss **pboss) {
} else {
float o = min(0, -5 + time/30.0);
float q = (time <= 150? 1 - pow(time/250.0, 2) : min(1, time/60.0));
boss_rule_extra(boss, max(1-time/300.0, base + ampl * s) * q);
if(o) {
boss_rule_extra(boss, max(1-time/300.0, base + ampl * s) - o);
@ -242,17 +242,17 @@ void process_boss(Boss **pboss) {
}
}
}
if(!boss->current->endtime && (boss->current->type != AT_Move && boss->dmg >= boss->current->dmglimit || time > boss->current->timeout)) {
boss->current->endtime = global.frames + extra * ATTACK_END_DELAY_EXTRA;
boss->current->finished = FINISH_WIN;
boss_kill_projectiles();
}
if(over) {
if(extra && boss->current->finished == FINISH_WIN)
spawn_items(boss->pos, 0, 0, 0, 1);
boss->current->rule(boss, EVENT_DEATH);
boss->dmg = boss->current->dmglimit + 1;
boss->current++;
@ -304,7 +304,7 @@ void start_attack(Boss *b, Attack *a) {
}
}
#if DEBUG
else if(a->type == AT_Spellcard) {
else if(a->type == AT_Spellcard || a->type == AT_ExtraSpell) {
warnx("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
}
#endif

View file

@ -24,8 +24,6 @@ void init_player(Player *plr) {
plr->continues = 0;
plr->points = 0;
plr->power = 4; // for extraspell testing
}
void prepare_player_for_next_stage(Player *plr) {
@ -234,8 +232,8 @@ void player_realdeath(Player *plr) {
if(plr->bombs < PLR_START_BOMBS)
plr->bombs = PLR_START_BOMBS;
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell) {
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell && global.stage->type != STAGE_SPELL) {
if(!global.boss->current->finished) {
global.boss->current->endtime = global.frames + ATTACK_END_DELAY_EXTRA;
global.boss->current->finished = FINISH_FAIL;

View file

@ -47,6 +47,8 @@ StageInfo stages[] = {
//
#define S STAGE_SPELL_BIT
#define E (STAGE_SPELL_BIT | STAGE_EXTRASPELL_BIT)
// Freeze Sign ~ Perfect Freeze
{S| 0, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Easy},
{S| 1, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Normal},
@ -202,6 +204,54 @@ StageInfo stages[] = {
{S| 97, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Normal},
{S| 98, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Hard},
{S| 99, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Lunatic},
//
// Extra spells
//
// Frost Sign ~ Crystal Blizzard
{E| 0, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+3, D_Easy},
{E| 1, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+3, D_Normal},
{E| 2, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+3, D_Hard},
{E| 3, stage1_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+3, D_Lunatic},
// RESERVED
/*
{E| 4, stage2_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+3, D_Easy},
{E| 5, stage2_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+3, D_Normal},
{E| 6, stage2_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+3, D_Hard},
{E| 7, stage2_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+3, D_Lunatic},
*/
// Firefly Sign ~ Moonlight Wraith
{E| 8, stage3_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+5, D_Easy},
{E| 9, stage3_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+5, D_Normal},
{E| 10, stage3_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+5, D_Hard},
{E| 11, stage3_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+5, D_Lunatic},
// RESERVED
/*
{E| 12, stage4_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {1, 1, 1}, stage4_spells+7, D_Easy},
{E| 13, stage4_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {1, 1, 1}, stage4_spells+7, D_Normal},
{E| 14, stage4_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {1, 1, 1}, stage4_spells+7, D_Hard},
{E| 15, stage4_spellpractice_loop, STAGE_SPELL, NULL, NULL, {0, 0, 0}, {1, 1, 1}, stage4_spells+7, D_Lunatic},
*/
// Circuit Sign ~ Overload
{E| 16, stage5_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+4, D_Easy},
{E| 17, stage5_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+4, D_Normal},
{E| 18, stage5_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+4, D_Hard},
{E| 19, stage5_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+4, D_Lunatic},
// RESERVED
/*
{E| 20, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+6, D_Easy},
{E| 21, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+6, D_Normal},
{E| 22, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+6, D_Hard},
{E| 23, stage6_spellpractice_loop, STAGE_SPELL, NULL, NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+6, D_Lunatic},
*/
#undef E
#undef S
{0}
@ -474,7 +524,7 @@ void draw_hud(void) {
glColor4f(1, 1, 1, 1.0);
} else {
float a = 1, s = 0, fadein = 1, fadeout = 1, fade = 1;
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell) {
fadein = min(1, -min(0, global.frames - global.boss->current->starttime) / (float)ATTACK_START_DELAY);
fadeout = (!!global.boss->current->finished) * (1 - (global.boss->current->endtime - global.frames) / (float)ATTACK_END_DELAY_EXTRA) / 0.74;
@ -483,7 +533,7 @@ void draw_hud(void) {
s = 1 - fade;
a = 0.5 + 0.5 * fade;
}
if(a != 1) glColor4f(a,a,a,a);
for(i = 0; i < global.plr.lifes; i++)
draw_texture(16*i,167, "star");
@ -595,8 +645,8 @@ void stage_draw(StageInfo *info, StageRule bgdraw, ShaderRule *shaderrules, int
draw_items();
draw_projectiles(global.projs);
draw_projectiles(global.particles);
draw_lasers(true);
draw_enemies(global.enemies);
draw_lasers(false);
@ -614,7 +664,7 @@ void stage_draw(StageInfo *info, StageRule bgdraw, ShaderRule *shaderrules, int
glPushMatrix();
if(global.shake_view) {
glTranslatef(global.shake_view*sin(global.frames),global.shake_view*sin(global.frames+3),0);
if(global.shake_view_fade) {
global.shake_view -= global.shake_view_fade;
if(global.shake_view <= 0)
@ -658,7 +708,7 @@ void apply_bg_shaders(ShaderRule *shaderrules) {
int t = global.frames - global.boss->current->starttime;
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[0].fbo);
global.boss->current->draw_rule(global.boss, t);
if(global.boss->current->type == AT_ExtraSpell)
draw_extraspell_bg(global.boss, t);

View file

@ -46,8 +46,9 @@ typedef enum {
typedef void (*StageRule)(void);
typedef void (*ShaderRule)(int);
// highest bit of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
// two highest bits of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
#define STAGE_SPELL_BIT 0x8000
#define STAGE_EXTRASPELL_BIT 0x4000
typedef enum StageType {
STAGE_STORY = 1,

View file

@ -17,11 +17,13 @@ void cirno_perfect_freeze(Boss*, int);
void cirno_crystal_rain(Boss*, int);
void cirno_icicle_fall(Boss*, int);
void cirno_pfreeze_bg(Boss*, int);
void cirno_crystal_blizzard(Boss*, int);
AttackInfo stage1_spells[] = {
{AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 32, 20000, cirno_perfect_freeze, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
{AT_Spellcard, "Freeze Sign ~ Crystal Rain", 28, 28000, cirno_crystal_rain, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
{AT_Spellcard, "Doom Sign ~ Icicle Fall", 35, 40000, cirno_icicle_fall, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
{AT_ExtraSpell, "Frost Sign ~ Crystal Blizzard", 60, 40000, cirno_crystal_blizzard, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
};
Dialog *stage1_dialog(void) {
@ -414,17 +416,13 @@ void cirno_superhardspellcard(Boss *c, int t) {
Boss *create_cirno(void) {
Boss* cirno = create_boss("Cirno", "cirno", -230 + 100.0*I);
boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro_boss, NULL);
// extra spell test
boss_add_attack(cirno, AT_ExtraSpell, "Frost Sign ~ Crystal Blizzard", 60, 40000, cirno_crystal_blizzard, cirno_pfreeze_bg);
/*
boss_add_attack(cirno, AT_Normal, "Iceplosion 0", 20, 20000, cirno_iceplosion0, NULL);
boss_add_attack_from_info(cirno, stage1_spells+1, false);
boss_add_attack(cirno, AT_Normal, "Iceplosion 1", 20, 20000, cirno_iceplosion1, NULL);
boss_add_attack_from_info(cirno, stage1_spells+2, false);
*/
start_attack(cirno, cirno->attacks);
return cirno;
}
@ -632,8 +630,7 @@ int stage1_tritoss(Enemy *e, int t) {
void stage1_events(void) {
TIMER(&global.timer);
AT(0)
global.timer = 5000;
/*
// graze testing
AT(0) {

View file

@ -18,6 +18,7 @@ void stage3_mid_a2(Boss*, int t);
void stage3_boss_a1(Boss*, int t);
void stage3_boss_a2(Boss*, int t);
void stage3_boss_a3(Boss*, int t);
void stage3_boss_extra(Boss*, int t);
AttackInfo stage3_spells[] = {
{AT_Spellcard, "Venom Sign ~ Deadly Dance", 25, 25000, stage3_mid_a1, stage3_mid_spellbg, BOSS_DEFAULT_GO_POS},
@ -25,6 +26,7 @@ AttackInfo stage3_spells[] = {
{AT_Spellcard, "Firefly Sign ~ Moonlight Rocket", 30, 20000, stage3_boss_a1, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
{AT_Spellcard, "Light Source ~ Wriggle Night Ignite", 25, 40000, stage3_boss_a2, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
{AT_Spellcard, "Bug Sign ~ Phosphaenus Hemipterus", 35, 30000, stage3_boss_a3, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
{AT_ExtraSpell, "Firefly Sign ~ Moonlight Wraith", 60, 150000, stage3_boss_extra, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
};
Dialog *stage3_dialog(void) {
@ -522,7 +524,7 @@ int stage3_boss_a1_slave(Enemy *e, int time) {
return ACTION_DESTROY;
int extra = boss->current->type == AT_ExtraSpell;
AT(EVENT_DEATH) {
free_ref(e->args[0]);
spawn_items(e->pos, 1, 1, 0, 0);
@ -543,10 +545,10 @@ int stage3_boss_a1_slave(Enemy *e, int time) {
int i; for(i = -d; i < d; ++i)
create_projectile2c("wave", e->pos, rgb(0.3 + 0.7 * psin(time / 30.0), 1.0, 0.3), accelerated, dir*0.5, cexp(I*(0.05*i+carg(dir))) * 0.005)->draw = ProjDrawAdd;
}
return 1;
}
if(!creal(e->args[3]) && !(time % 140)) {
float dt = 70;
@ -786,32 +788,32 @@ void stage3_boss_intro(Boss *boss, int time) {
void stage3_boss_extra(Boss *boss, int time) {
//int t = time % 700;
TIMER(&time);
if(time < 0) {
GO_TO(boss, VIEWPORT_W/2.0+100I, 0.1);
return;
}
AT(0) {
int i, j, cnt = 1 + global.diff;
for(j = -1; j < 2; j += 2) for(i = 0; i < cnt; ++i)
create_enemy3c(boss->pos, ENEMY_IMMUNE, Swirl, stage3_boss_a1_slave, add_ref(boss), i*2*M_PI/cnt, j);
return;
}
int cnt = 7;
int step = 10;
FROM_TO_INT(60, 900000000, 300, cnt*step, step) {
int i; for(i = 0; i < 2; ++i) {
double Oy = VIEWPORT_H*_ni/(double)cnt;
complex origin = VIEWPORT_W*i + Oy*I;
complex target = global.plr.pos;
complex dist = target - origin;
complex accel = 0.05 * cexp(I*carg(dist));
float deathtime = sqrt(2*cabs(dist)/cabs(accel));
float c = 0.8 * psin(_ni*2*M_PI/cnt);
Laser *l = create_lasercurve2c(origin, deathtime/3, deathtime, rgb(1 - c, 0.2, 0.2 + c), las_accel, 0, accel);
create_projectile3c("ball", origin, rgb(1.0, 0.5, 0.5), stage3_boss_a1_laserbullet, add_ref(l), deathtime - 1, 0)->draw = ProjDrawAdd;
@ -822,17 +824,13 @@ void stage3_boss_extra(Boss *boss, int time) {
Boss* stage3_create_boss(void) {
Boss *wriggle = create_boss("Wriggle EX", "wriggleex", VIEWPORT_W/2 - 200.0*I);
boss_add_attack(wriggle, AT_Move, "Introduction", 2, 0, stage3_boss_intro, NULL);
boss_add_attack(wriggle, AT_ExtraSpell, "Firefly Sign ~ Moonlight Wraith", 60, 150000, stage3_boss_extra, stage3_boss_spellbg);
/*
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea1, NULL);
boss_add_attack_from_info(wriggle, stage3_spells+2, false);
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea2, NULL);
boss_add_attack_from_info(wriggle, stage3_spells+3, false);
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea3, NULL);
boss_add_attack_from_info(wriggle, stage3_spells+4, false);
*/
start_attack(wriggle, wriggle->attacks);
return wriggle;
}
@ -840,9 +838,6 @@ Boss* stage3_create_boss(void) {
void stage3_events(void) {
TIMER(&global.timer);
AT(0)
global.timer = 5300;
FROM_TO(160, 300, 10) {
tsrand_fill(3);
create_enemy1c(VIEWPORT_W/2 + 20 * anfrand(0) + (VIEWPORT_H/4 + 20 * anfrand(1))*I, 200, Swirl, stage3_enterswirl, I * 3 + anfrand(2) * 3);

View file

@ -15,12 +15,14 @@ void iku_atmospheric(Boss*, int);
void iku_lightning(Boss*, int);
void iku_cathode(Boss*, int);
void iku_induction(Boss*, int);
void iku_extra(Boss*, int);
AttackInfo stage5_spells[] = {
{AT_Spellcard, "High Voltage ~ Atmospheric Discharge", 30, 30000, iku_atmospheric, iku_spell_bg, BOSS_DEFAULT_GO_POS},
{AT_Spellcard, "Charge Sign ~ Artificial Lightning", 30, 35000, iku_lightning, iku_spell_bg, BOSS_DEFAULT_GO_POS},
{AT_Spellcard, "Spark Sign ~ Natural Cathode", 30, 35000, iku_cathode, iku_spell_bg, BOSS_DEFAULT_GO_POS},
{AT_Spellcard, "Current Sign ~ Induction", 30, 35000, iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS},
{AT_ExtraSpell, "Circuit Sign ~ Overload", 60000, 150000, iku_extra, iku_spell_bg, BOSS_DEFAULT_GO_POS},
};
Dialog *stage5_post_mid_dialog(void) {
@ -33,14 +35,12 @@ Dialog *stage5_post_mid_dialog(void) {
Dialog *stage5_boss_dialog(void) {
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/iku");
/*
dadd_msg(d, Left, "Finally!");
dadd_msg(d, Right, "Stop following me!");
dadd_msg(d, Left, "Why? You arent involved in this, are you?");
dadd_msg(d, Right, "I dont have time for your suspicions now.");
dadd_msg(d, Left, "Sounds very suspicious, actually.");
dadd_msg(d, Right, "Okay, lets just get this over with.");
*/
dadd_msg(d, BGM, "bgm_stage5boss");
return d;
}
@ -637,9 +637,6 @@ Boss *create_iku(void) {
Boss *b = create_boss("Nagae Iku", "iku", VIEWPORT_W/2-200.0*I);
boss_add_attack(b, AT_Move, "Introduction", 3, 0, iku_intro, NULL);
boss_add_attack(b, AT_ExtraSpell, "Circuit Sign ~ Overload", 60000, 150000, iku_extra, iku_spell_bg);
/*
boss_add_attack(b, AT_Normal, "Bolts1", 20, 20000, iku_bolts, NULL);
boss_add_attack_from_info(b, stage5_spells+0, false);
boss_add_attack(b, AT_Normal, "Bolts2", 25, 20000, iku_bolts2, NULL);
@ -647,7 +644,6 @@ Boss *create_iku(void) {
boss_add_attack(b, AT_Normal, "Bolts3", 20, 20000, iku_bolts3, NULL);
boss_add_attack_from_info(b, stage5_spells+2, false);
boss_add_attack_from_info(b, stage5_spells+3, false);
*/
return b;
}
@ -655,9 +651,6 @@ Boss *create_iku(void) {
void stage5_events(void) {
TIMER(&global.timer);
AT(0)
global.timer = 5300;
FROM_TO(60, 120, 10)
create_enemy1c(VIEWPORT_W+70.0*I+50*_i*I, 300, Fairy, stage5_greeter, -3);