stage3: preliminary coroutinization (#197)

* first enemy of Stage 3 converted

* review suggestions

* add interval for burst_swirls

* mid-commit

* fairy group (second spawned enemies)

* forgot to use my own variable

* comment changes

* better understanding of second arg of create_enemy*

* fix subtasks (wasn't using them the correct way)

* swirls that go from one side to the other

* burst fairies complete

* all complete up until midboss (stage 3 coroutines)

* remove sub-rule for projectiles in charge_fairy

* entire stage on coroutines now (boss spellcards missing)

* rip out more old/dead code, make file better organized

* timing changes

* remove old background (looks jank now with new timing)

* PR review changes

* slight readability changes

* Scuttle lethal_bite implemented

* PR changes (ignore wriggle, she's still a WIP)

* revert Info.plist entry (for separate PR)

* finish(?) Scuttle's deadly dance, plus some PR changes
This commit is contained in:
Alice D 2020-03-18 23:25:25 -04:00 committed by Andrei Alexeyev
parent 12af051d48
commit db6bb13326
No known key found for this signature in database
GPG key ID: 72D26128040B9690
12 changed files with 804 additions and 1239 deletions

View file

@ -13,103 +13,17 @@
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
static int wriggle_nonspell_slave(Enemy *e, int time) {
TIMER(&time)
int level = e->args[3];
float angle = e->args[2] * (time / 70.0 + e->args[1]);
cmplx dir = cexp(I*angle);
Boss *boss = (Boss*)REF(e->args[0]);
if(!boss)
return ACTION_DESTROY;
AT(EVENT_DEATH) {
free_ref(e->args[0]);
return 1;
}
if(time < 0)
return 1;
GO_TO(e, boss->pos + (100 + 20 * e->args[2] * sin(time / 100.0)) * dir, 0.03)
int d = 10 - global.diff;
if(level > 2)
d += 4;
if(!(time % d)) {
play_sound("shot1");
PROJECTILE(
.proto = pp_rice,
.pos = e->pos,
.color = RGB(0.7, 0.2, 0.1),
.rule = linear,
.args = { 3 * cexp(I*carg(boss->pos - e->pos)) },
);
if(!(time % (d*2)) || level > 1) {
PROJECTILE(
.proto = pp_thickrice,
.pos = e->pos,
.color = RGB(0.7, 0.7, 0.1),
.rule = linear,
.args = { 2.5 * cexp(I*carg(boss->pos - e->pos)) },
);
}
if(level > 2) {
PROJECTILE(
.proto = pp_wave,
.pos = e->pos,
.color = RGB(0.3, 0.1 + 0.6 * psin(time / 25.0), 0.7),
.rule = linear,
.args = { 2 * cexp(I*carg(boss->pos - e->pos)) },
);
}
}
return 1;
DEFINE_EXTERN_TASK(stage3_boss_nonspell_1) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}
static void wriggle_nonspell_common(Boss *boss, int time, int level) {
TIMER(&time)
int i, j, cnt = 3 + global.diff;
AT(0) for(j = -1; j < 2; j += 2) for(i = 0; i < cnt; ++i)
create_enemy4c(boss->pos, ENEMY_IMMUNE, wriggle_slave_visual, wriggle_nonspell_slave, add_ref(boss), i*2*M_PI/cnt, j, level);
AT(EVENT_DEATH) {
enemy_kill_all(&global.enemies);
return;
}
if(time < 0) {
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/3, 0.05)
return;
}
FROM_TO(120, 240, 1)
GO_TO(boss, VIEWPORT_W/3 + VIEWPORT_H*I/3, 0.03)
FROM_TO(360, 480, 1)
GO_TO(boss, VIEWPORT_W - VIEWPORT_W/3 + VIEWPORT_H*I/3, 0.03)
FROM_TO(600, 720, 1)
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/3, 0.03)
DEFINE_EXTERN_TASK(stage3_boss_nonspell_2) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}
void stage3_boss_nonspell1(Boss *boss, int time) {
wriggle_nonspell_common(boss, time, 1);
}
void stage3_boss_nonspell2(Boss *boss, int time) {
wriggle_nonspell_common(boss, time, 2);
}
void stage3_boss_nonspell3(Boss *boss, int time) {
wriggle_nonspell_common(boss, time, 3);
DEFINE_EXTERN_TASK(stage3_boss_nonspell_3) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}

View file

@ -13,87 +13,77 @@
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
TASK(midboss_delaymove, { BoxedBoss boss; } ) {
Boss *boss = TASK_BIND(ARGS.boss);
static int scuttle_lethbite_proj(Projectile *p, int time) {
if(time < 0) {
return ACTION_ACK;
}
boss->move.attraction_point = 5*VIEWPORT_W/6 + 200*I;
boss->move.attraction = 0.001;
}
#define A0_PROJ_START 120
#define A0_PROJ_CHARGE 20
TIMER(&time)
DEFINE_EXTERN_TASK(stage3_midboss_nonspell_1) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
FROM_TO(A0_PROJ_START, A0_PROJ_START + A0_PROJ_CHARGE, 1)
return 1;
int difficulty = difficulty_value(1, 2, 3, 4);
int intensity = difficulty_value(18, 19, 20, 21);
int velocity_intensity = difficulty_value(2, 3, 4, 5);
INVOKE_SUBTASK_DELAYED(400, midboss_delaymove, ENT_BOX(boss));
AT(A0_PROJ_START + A0_PROJ_CHARGE + 1) if(p->type != PROJ_DEAD) {
p->args[1] = 3;
p->args[0] = (3 + 2 * global.diff / (float)D_Lunatic) * cexp(I*carg(global.plr.pos - p->pos));
for(;;) {
DECLARE_ENT_ARRAY(Projectile, projs, intensity*4);
int cnt = 3, i;
for(i = 0; i < cnt; ++i) {
tsrand_fill(2);
PARTICLE(
.sprite = "smoothdot",
.color = RGBA(0.8, 0.6, 0.6, 0),
.draw_rule = Shrink,
.rule = enemy_flare,
.timeout = 100,
.args = {
cexp(I*(M_PI*anfrand(0))) * (1 + afrand(1)),
add_ref(p)
},
// fly through Scuttle, wind up on other side in a starburst pattern
for(int i = 0; i < intensity; ++i) {
cmplx v = (2 - psin((fmax(3, velocity_intensity) * 2 * M_PI * i / (float)intensity) + i)) * cdir(2 * M_PI / intensity * i);
ENT_ARRAY_ADD(&projs,
PROJECTILE(
.proto = pp_wave,
.pos = boss->pos - v * 50,
.color = i % 2 ? RGB(0.7, 0.3, 0.0) : RGB(0.3, .7, 0.0),
.move = move_asymptotic_simple(v, 2.0)
)
);
}
float offset = global.frames/15.0;
if(global.diff > D_Hard && global.boss) {
offset = M_PI+carg(global.plr.pos-global.boss->pos);
WAIT(80);
// halt acceleration for a moment
ENT_ARRAY_FOREACH(&projs, Projectile *p, {
p->move.acceleration = 0;
});
WAIT(30);
// change direction, fly towards player
ENT_ARRAY_FOREACH(&projs, Projectile *p, {
int count = 6;
// when the shot "releases", add a bunch of particles and some extra bullets
for(int i = 0; i < count; ++i) {
PARTICLE(
.sprite = "smoothdot",
.pos = p->pos,
.color = RGBA(0.8, 0.6, 0.6, 0),
.timeout = 100,
.draw_rule = pdraw_timeout_scalefade(0, 0.8, 1, 0),
.move = move_asymptotic_simple(p->move.velocity + rng_dir(), 0.1)
);
real offset = global.frames/15.0;
if(global.diff > D_Hard && global.boss) {
offset = M_PI + carg(global.plr.pos - global.boss->pos);
}
PROJECTILE(
.proto = pp_thickrice,
.pos = p->pos,
.color = RGB(0.4, 0.3, 1.0),
.move = move_linear(-cdir(((i * 2 * M_PI/count + offset)) * (1.0 + (difficulty > 2))))
);
}
spawn_projectile_highlight_effect(p);
p->move = move_linear((3 + (2.0 * difficulty) / 4.0) * (cnormalize(global.plr.pos - p->pos)));
PROJECTILE(
.proto = pp_thickrice,
.pos = p->pos,
.color = RGB(0.4, 0.3, 1.0),
.rule = linear,
.args = {
-cexp(I*(i*2*M_PI/cnt + offset)) * (1.0 + (global.diff > D_Normal))
},
);
}
play_sound("redirect");
play_sound("shot1");
spawn_projectile_highlight_effect(p);
}
return asymptotic(p, time);
#undef A0_PROJ_START
#undef A0_PROJ_CHARGE
}
void stage3_midboss_nonspell1(Boss *boss, int time) {
int i;
TIMER(&time)
GO_TO(boss, VIEWPORT_W/2+VIEWPORT_W/3*sin(time/300) + I*cimag(boss->pos), 0.01)
FROM_TO_INT(0, 90000, 72 + 6 * (D_Lunatic - global.diff), 0, 1) {
int cnt = 21 - 1 * (D_Lunatic - global.diff);
for(i = 0; i < cnt; ++i) {
cmplx v = (2 - psin((fmax(3, global.diff+1)*2*M_PI*i/(float)cnt) + time)) * cexp(I*2*M_PI/cnt*i);
PROJECTILE(
.proto = pp_wave,
.pos = boss->pos - v * 50,
.color = _i % 2? RGB(0.7, 0.3, 0.0) : RGB(0.3, .7, 0.0),
.rule = scuttle_lethbite_proj,
.args = { v, 2.0 },
);
}
// FIXME: better sound
play_sound("shot_special1");
});
}
}

View file

@ -11,9 +11,7 @@
#include "boss.h"
void stage3_midboss_nonspell1(Boss *boss, int time);
void stage3_boss_nonspell1(Boss *boss, int time);
void stage3_boss_nonspell2(Boss *boss, int time);
void stage3_boss_nonspell3(Boss *boss, int time);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_midboss_nonspell_1, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_boss_nonspell_1, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_boss_nonspell_2, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_boss_nonspell_3, BossAttack);

View file

@ -16,106 +16,84 @@
MODERNIZE_THIS_FILE_AND_REMOVE_ME
static int scuttle_poison(Projectile *p, int time) {
int result = accelerated(p, time);
TASK(deadly_dance_proj, { BoxedProjectile p; int t; int i; }) {
if(time < 0)
return result;
Projectile *p = TASK_BIND(ARGS.p);
if(!(time % (57 - global.diff * 3)) && p->type != PROJ_DEAD) {
float a = p->args[2];
float t = p->args[3] + time;
PROJECTILE(
.proto = (frand() > 0.5)? pp_thickrice : pp_rice,
.pos = p->pos,
.color = RGB(0.3, 0.7 + 0.3 * psin(a/3.0 + t/20.0), 0.3),
.rule = accelerated,
.args = {
0,
0.005*cexp(I*(M_PI*2 * sin(a/5.0 + t/20.0))),
},
);
play_sound("redirect");
}
return result;
int t = ARGS.t;
int i = ARGS.i;
double a = (M_PI/(5 + global.diff) * i * 2);
PROJECTILE(
.proto = rng_chance(0.5) ? pp_thickrice : pp_rice,
.pos = p->pos,
.color = RGB(0.3, 0.7 + 0.3 * psin(a/3.0 + t/20.0), 0.3),
.move = move_accelerated(0, 0.005 * cdir((M_PI * 2 * sin(a / 5.0 + t / 20.0))))
);
}
void scuttle_deadly_dance(Boss *boss, int time) {
int i;
TIMER(&time)
DEFINE_EXTERN_TASK(stage3_spell_deadly_dance) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
if(time < 0) {
return;
}
aniplayer_queue(&boss->ani, "dance", 0);
int intensity = difficulty_value(15, 18, 21, 24);
AT(0) {
aniplayer_queue(&boss->ani, "dance", 0);
}
play_sfx_loop("shot1_loop");
int i;
for(int time = 0; time < 1000; ++time) {
WAIT(1);
FROM_TO(0, 120, 1)
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/2, 0.03)
DECLARE_ENT_ARRAY(Projectile, projs, intensity*2);
if(time > 30) {
float angle_ofs = frand() * M_PI * 2;
double t = time * 1.5 * (0.4 + 0.3 * global.diff);
double moverad = fmin(160, time/2.7);
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/2 + sin(t/50.0) * moverad * cexp(I * M_PI_2 * t/100.0), 0.03)
real angle_ofs = rng_f32() * M_PI * 2;
double t = time * 1.5 * (0.4 + 0.3 * global.diff);
double moverad = fmin(160, time/2.7);
if(!(time % 70)) {
for(i = 0; i < 15; ++i) {
double a = M_PI/(5 + global.diff) * i * 2;
PROJECTILE(
.proto = pp_wave,
.pos = boss->pos,
.color = RGB(0.3, 0.3 + 0.7 * psin(a*3 + time/50.0), 0.3),
.rule = scuttle_poison,
.args = {
0,
0.02 * cexp(I*(angle_ofs+a+time/10.0)),
a,
time
}
);
}
boss->pos = VIEWPORT_W/2 + VIEWPORT_H*I/2 + sin(t/50.0) * moverad * cdir(M_PI_2 * t/100.0);
play_sound("shot_special1");
}
if(!(time % 70)) {
for(i = 0; i < intensity; ++i) {
double a = (M_PI/(5 + global.diff) * i * 2);
ENT_ARRAY_ADD(&projs, PROJECTILE(
.proto = pp_wave,
.pos = boss->pos,
.color = RGB(0.3, 0.3 + 0.7 * psin((M_PI/(5 + global.diff) * i * 2) * 3 + time/50.0), 0.3),
.move = move_accelerated(0, 0.02 * cdir(angle_ofs + a + time/10.0)),
));
}
ENT_ARRAY_FOREACH(&projs, Projectile *p, {
INVOKE_SUBTASK_DELAYED(150, deadly_dance_proj, ENT_BOX(p), t, i);
});
}
if(global.diff > D_Easy && !(time % 35)) {
int cnt = global.diff * 2;
for(i = 0; i < cnt; ++i) {
PROJECTILE(
.proto = pp_ball,
.pos = boss->pos,
.color = RGB(1.0, 1.0, 0.3),
.rule = asymptotic,
.args = {
(0.5 + 3 * psin(time + M_PI/3*2*i)) * cexp(I*(angle_ofs + time / 20.0 + M_PI/cnt*i*2)),
1.5
}
);
}
if(global.diff > D_Easy && !(time % 35)) {
int count = difficulty_value(2, 4, 6, 8);
for(i = 0; i < count; ++i) {
PROJECTILE(
.proto = pp_ball,
.pos = boss->pos,
.color = RGB(1.0, 1.0, 0.3),
.move = move_asymptotic_simple(
(0.5 + 3 * psin(time + M_PI / 3 * 2 * i)) * cdir(angle_ofs + time / 20.0 + M_PI / count * i * 2),
1.5
)
);
}
}
play_sound("shot1");
}
}
play_sound("shot1");
if(!(time % 3)) {
for(i = -1; i < 2; i += 2) {
double c = psin(time/10.0);
PROJECTILE(
.proto = pp_crystal,
.pos = boss->pos,
.color = RGBA_MUL_ALPHA(0.3 + c * 0.7, 0.6 - c * 0.3, 0.3, 0.7),
.rule = linear,
.args = {
10 * cexp(I*(carg(global.plr.pos - boss->pos) + (M_PI/4.0 * i * (1-time/2500.0)) * (1 - 0.5 * psin(time/15.0))))
}
);
}
}
if(!(time % 3)) {
for(i = -1; i < 2; i += 2) {
double c = psin(time/10.0);
PROJECTILE(
.proto = pp_crystal,
.pos = boss->pos,
.color = RGBA_MUL_ALPHA(0.3 + c * 0.7, 0.6 - c * 0.3, 0.3, 0.7),
.move = move_linear(
10 * (cnormalize(global.plr.pos - boss->pos) + (M_PI/4.0 * i * (1 - time / 2500.0)) * (1 - 0.5 * psin(time / 15.0)))
)
);
}
}
}
}

View file

@ -14,110 +14,7 @@
#include "common_tasks.h"
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
DEPRECATED_DRAW_RULE
static void wriggle_fstorm_proj_draw(Projectile *p, int time, ProjDrawRuleArgs args) {
float f = 1-fmin(time/60.0,1);
r_mat_mv_push();
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
r_mat_mv_rotate(p->angle + M_PI/2, 0, 0, 1);
ProjDrawCore(p, &p->color);
if(f > 0) {
// TODO: Maybe convert this into a particle effect?
Sprite *s = p->sprite;
Color c = p->color;
c.a = 0;
p->sprite = get_sprite("proj/ball");
r_mat_mv_scale(f,f,f);
ProjDrawCore(p, &c);
p->sprite = s;
}
r_mat_mv_pop();
}
static int wriggle_fstorm_proj(Projectile *p, int time) {
if(time < 0) {
return ACTION_ACK;
}
if(cabs(global.plr.pos-p->pos) > 100) {
p->args[2]+=1;
} else {
p->args[2]-=1;
if(creal(p->args[2]) < 0)
p->args[2] = 0;
}
int turntime = rint(creal(p->args[0]));
int t = rint(creal(p->args[2]));
if(t < turntime) {
float f = t/(float)turntime;
p->color = *RGB(0.3+0.7*(1 - pow(1 - f, 4)), 0.3+0.3*f*f, 0.7-0.7*f);
}
if(t == turntime && global.boss) {
p->args[1] = global.boss->pos-p->pos;
p->args[1] *= 2/cabs(p->args[1]);
p->angle = carg(p->args[1]);
p->birthtime = global.frames;
p->draw_rule = (ProjDrawRule) { wriggle_fstorm_proj_draw };
p->sprite = NULL;
projectile_set_prototype(p, pp_rice);
spawn_projectile_highlight_effect(p);
for(int i = 0; i < 3; ++i) {
tsrand_fill(2);
PARTICLE(
.sprite = "flare",
.pos = p->pos,
.rule = linear,
.timeout = 60,
.args = { (1+afrand(0))*cexp(I*tsrand_a(1)) },
.draw_rule = Shrink,
);
}
play_sound_ex("redirect", 3, false);
}
p->pos += p->args[1];
return ACTION_NONE;
}
void wriggle_firefly_storm(Boss *boss, int time) {
TIMER(&time)
if(time < 0) {
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/2, 0.05)
return;
}
bool lun = global.diff == D_Lunatic;
AT(0) {
aniplayer_queue(&boss->ani,"fly",0);
}
FROM_TO_SND("shot1_loop", 30, 9000, 2) {
int i, cnt = 2;
for(i = 0; i < cnt; ++i) {
float r = tanh(sin(_i/200.));
float v = lun ? cos(_i/150.)/pow(cosh(atanh(r)),2) : 0.5;
cmplx pos = 230*cexp(I*(_i*0.301+2*M_PI/cnt*i))*r;
PROJECTILE(
.proto = (global.diff >= D_Hard) && !(i%10) ? pp_bigball : pp_ball,
.pos = boss->pos+pos,
.color = RGB(0.2,0.2,0.6),
.rule = wriggle_fstorm_proj,
.args = {
(global.diff == D_Easy) ? 40 : 100-25*(!lun)-20*(global.diff == D_Normal),
cexp(I*(!lun)*0.6)*pos/cabs(pos)*(1+v)
},
);
}
}
DEFINE_EXTERN_TASK(stage3_spell_firefly_storm) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}

View file

@ -14,111 +14,7 @@
#include "common_tasks.h"
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
static void wriggle_singularity_laser_logic(Laser *l, int time) {
if(time == EVENT_BIRTH) {
l->width = 0;
l->speed = 0;
l->timeshift = l->timespan;
l->unclearable = true;
return;
}
if(time == 140) {
play_sound("laser1");
}
laser_charge(l, time, 150, 10 + 10 * psin(l->args[0] + time / 60.0));
l->args[3] = time / 10.0;
l->args[0] *= cexp(I*(M_PI/500.0) * (0.7 + 0.35 * global.diff));
l->color = *HSLA((carg(l->args[0]) + M_PI) / (M_PI * 2), 1.0, 0.5, 0.0);
}
void wriggle_light_singularity(Boss *boss, int time) {
TIMER(&time)
AT(EVENT_DEATH) {
return;
}
time -= 120;
if(time < 0) {
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/2, 0.05)
return;
}
AT(0) {
int cnt = 2 + global.diff;
for(int i = 0; i < cnt; ++i) {
double aofs = 0;
if(global.diff == D_Hard || global.diff == D_Easy) {
aofs = 0.7;
}
cmplx vel = 2 * cexp(I*(aofs + M_PI / 4 + M_PI * 2 * i / (double)cnt));
double amp = (4.0/cnt) * (M_PI/5.0);
double freq = 0.05;
create_laser(boss->pos, 200, 10000, RGBA(0.0, 0.2, 1.0, 0.0), las_sine_expanding,
wriggle_singularity_laser_logic, vel, amp, freq, 0);
}
play_sound("charge_generic");
aniplayer_queue(&boss->ani, "main", 0);
}
if(time > 120) {
play_sfx_loop("shot1_loop");
}
if(time == 0) {
return;
}
if(!((time+30) % 300)) {
aniplayer_queue(&boss->ani, "specialshot_charge", 1);
aniplayer_queue(&boss->ani, "specialshot_release", 1);
aniplayer_queue(&boss->ani, "main", 0);
}
if(!(time % 300)) {
ProjPrototype *ptype = NULL;
switch(time / 300 - 1) {
case 0: ptype = pp_thickrice; break;
case 1: ptype = pp_rice; break;
case 2: ptype = pp_bullet; break;
case 3: ptype = pp_wave; break;
case 4: ptype = pp_ball; break;
case 5: ptype = pp_plainball; break;
case 6: ptype = pp_bigball; break;
default: ptype = pp_soul; break;
}
int cnt = 6 + 2 * global.diff;
float colorofs = frand();
for(int i = 0; i < cnt; ++i) {
double a = ((M_PI*2.0*i)/cnt);
cmplx dir = cexp(I*a);
PROJECTILE(
.proto = ptype,
.pos = boss->pos,
.color = HSLA(a/(M_PI*2) + colorofs, 1.0, 0.5, 0),
.rule = asymptotic,
.args = {
dir * (1.2 - 0.2 * global.diff),
20
},
);
}
play_sound("shot_special1");
}
DEFINE_EXTERN_TASK(stage3_spell_light_singularity) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}

View file

@ -14,21 +14,7 @@
#include "common_tasks.h"
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
void wriggle_moonlight_rocket(Boss *boss, int time) {
int i, j, cnt = 1 + global.diff;
TIMER(&time)
AT(EVENT_DEATH) {
enemy_kill_all(&global.enemies);
return;
}
if(time < 0)
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/2.5, 0.05)
else if(time == 0) {
for(j = -1; j < 2; j += 2) for(i = 0; i < cnt; ++i)
create_enemy3c(boss->pos, ENEMY_IMMUNE, wriggle_slave_visual, wriggle_spell_slave, add_ref(boss), i*2*M_PI/cnt, j);
}
DEFINE_EXTERN_TASK(stage3_spell_moonlight_rocket) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}

View file

@ -11,110 +11,10 @@
#include "spells.h"
#include "../wriggle.h"
#include "refs.h"
#include "common_tasks.h"
#include "global.h"
MODERNIZE_THIS_FILE_AND_REMOVE_ME
static int wriggle_ignite_laserbullet(Projectile *p, int time) {
if(time == EVENT_DEATH) {
free_ref(p->args[0]);
return ACTION_ACK;
} else if(time < 0) {
return ACTION_ACK;
}
Laser *laser = (Laser*)REF(p->args[0]);
if(laser) {
p->args[3] = laser->prule(laser, time - p->args[1]) - p->pos;
}
p->angle = carg(p->args[3]);
p->pos = p->pos + p->args[3];
return ACTION_NONE;
}
static void wriggle_ignite_warnlaser_logic(Laser *l, int time) {
if(time == EVENT_BIRTH) {
l->width = 0;
return;
}
if(time < 0) {
return;
}
if(time == 90) {
play_sound_ex("laser1", 30, false);
}
laser_charge(l, time, 90, 10);
l->color = *color_lerp(RGBA(0.2, 0.2, 1, 0), RGBA(1, 0.2, 0.2, 0), time / l->deathtime);
}
static void wriggle_ignite_warnlaser(Laser *l) {
float f = 6;
create_laser(l->pos, 90, 120, RGBA(1, 1, 1, 0), l->prule, wriggle_ignite_warnlaser_logic, f*l->args[0], l->args[1], f*l->args[2], l->args[3]);
}
void wriggle_night_ignite(Boss *boss, int time) {
TIMER(&time)
float dfactor = global.diff / (float)D_Lunatic;
if(time == EVENT_DEATH) {
enemy_kill_all(&global.enemies);
return;
}
if(time < 0) {
GO_TO(boss, VIEWPORT_W/2 + VIEWPORT_H*I/3, 0.05)
return;
}
AT(0) for(int j = -1; j < 2; j += 2) for(int i = 0; i < 7; ++i) {
create_enemy4c(boss->pos, ENEMY_IMMUNE, wriggle_slave_visual, wriggle_spell_slave, add_ref(boss), i*2*M_PI/7, j, 1);
}
FROM_TO_INT(0, 1000000, 180, 120, 10) {
float dt = 200;
float lt = 100 * dfactor;
float a = _ni*M_PI/2.5 + _i + time;
float b = 0.3;
float c = 0.3;
cmplx vel = 2 * cexp(I*a);
double amp = M_PI/5;
double freq = 0.05;
Laser *l1 = create_lasercurve3c(boss->pos, lt, dt, RGBA(b, b, 1.0, 0.0), las_sine_expanding, vel, amp, freq);
wriggle_ignite_warnlaser(l1);
Laser *l2 = create_lasercurve3c(boss->pos, lt * 1.5, dt, RGBA(1.0, b, b, 0.0), las_sine_expanding, vel, amp, freq - 0.002 * fmin(global.diff, D_Hard));
wriggle_ignite_warnlaser(l2);
Laser *l3 = create_lasercurve3c(boss->pos, lt, dt, RGBA(b, b, 1.0, 0.0), las_sine_expanding, vel, amp, freq - 0.004 * fmin(global.diff, D_Hard));
wriggle_ignite_warnlaser(l3);
for(int i = 0; i < 5 + 15 * dfactor; ++i) {
#define LASERBULLLET(pproto, clr, laser) \
PROJECTILE(.proto = (pproto), .pos = boss->pos, .color = (clr), .rule = wriggle_ignite_laserbullet, .args = { add_ref(laser), i })
LASERBULLLET(pp_plainball, RGBA(c, c, 1.0, 0), l1);
LASERBULLLET(pp_bigball, RGBA(1.0, c, c, 0), l2);
LASERBULLLET(pp_plainball, RGBA(c, c, 1.0, 0), l3);
#undef LASERBULLLET
// FIXME: better sound
play_sound("shot1");
}
// FIXME: better sound
play_sound_ex("shot_special1", 1, false);
}
DEFINE_EXTERN_TASK(stage3_spell_night_ignite) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
BEGIN_BOSS_ATTACK(&ARGS);
}

View file

@ -11,8 +11,8 @@
#include "boss.h"
void scuttle_deadly_dance(Boss*, int t);
void wriggle_moonlight_rocket(Boss*, int t);
void wriggle_night_ignite(Boss*, int t);
void wriggle_firefly_storm(Boss*, int t);
void wriggle_light_singularity(Boss*, int t);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_spell_firefly_storm, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_spell_light_singularity, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_spell_moonlight_rocket, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_spell_night_ignite, BossAttack);
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage3_spell_deadly_dance, BossAttack);

View file

@ -15,8 +15,6 @@
#include "scuttle.h"
#include "spells/spells.h"
#include "timeline.h"
#include "wriggle.h"
#include "scuttle.h"
#include "global.h"
#include "portrait.h"
@ -31,28 +29,28 @@ struct stage3_spells_s stage3_spells = {
.mid = {
.deadly_dance = {
{ 0, 1, 2, 3}, AT_SurvivalSpell, "Venom Sign “Deadly Dance”", 14, 40000,
scuttle_deadly_dance, stage3_draw_scuttle_spellbg, BOSS_DEFAULT_GO_POS, 3
NULL, stage3_draw_scuttle_spellbg, VIEWPORT_W/2.0+100*I, 1, TASK_INDIRECT_INIT(BossAttack, stage3_spell_deadly_dance)
},
},
.boss = {
.moonlight_rocket = {
{ 6, 7, 8, 9}, AT_Spellcard, "Firefly Sign “Moonlight Rocket”", 40, 40000,
wriggle_moonlight_rocket, stage3_draw_wriggle_spellbg, BOSS_DEFAULT_GO_POS, 3
NULL, stage3_draw_wriggle_spellbg, VIEWPORT_W/2.0+100*I, 1, TASK_INDIRECT_INIT(BossAttack, stage3_spell_moonlight_rocket)
},
.wriggle_night_ignite = {
{10, 11, 12, 13}, AT_Spellcard, "Light Source “Wriggle Night Ignite”", 50, 46000,
wriggle_night_ignite, stage3_draw_wriggle_spellbg, BOSS_DEFAULT_GO_POS, 3
NULL, stage3_draw_wriggle_spellbg, VIEWPORT_W/2.0+100*I, 1, TASK_INDIRECT_INIT(BossAttack, stage3_spell_night_ignite)
},
.firefly_storm = {
{14, 15, 16, 17}, AT_Spellcard, "Bug Sign “Firefly Storm”", 45, 45000,
wriggle_firefly_storm, stage3_draw_wriggle_spellbg, BOSS_DEFAULT_GO_POS, 3
NULL, stage3_draw_wriggle_spellbg, VIEWPORT_W/2.0+100*I, 1, TASK_INDIRECT_INIT(BossAttack, stage3_spell_firefly_storm)
},
},
.extra.light_singularity = {
{ 0, 1, 2, 3}, AT_ExtraSpell, "Lamp Sign “Light Singularity”", 75, 45000,
wriggle_light_singularity, stage3_draw_wriggle_spellbg, BOSS_DEFAULT_GO_POS, 3
NULL, stage3_draw_wriggle_spellbg, VIEWPORT_W/2.0+100*I, 1, TASK_INDIRECT_INIT(BossAttack, stage3_spell_light_singularity)
},
};
@ -61,6 +59,7 @@ static void stage3_start(void) {
stage3_bg_init_fullstage();
stage_start_bgm("stage3");
stage_set_voltage_thresholds(50, 125, 300, 600);
INVOKE_TASK(stage3_timeline);
}
static void stage3_spellpractice_start(void) {
@ -131,7 +130,6 @@ StageProcs stage3_procs = {
.draw = stage3_draw,
.end = stage3_end,
.preload = stage3_preload,
.event = stage3_events,
.shader_rules = stage3_bg_effects,
.postprocess_rules = stage3_postprocess,
.spellpractice_procs = &(StageProcs) {

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,6 @@
#pragma once
#include "taisei.h"
void stage3_events(void);
#include "coroutine.h"
#define STAGE3_MIDBOSS_TIME 1765
DECLARE_EXTERN_TASK(stage3_timeline, NO_ARGS);