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:
parent
12af051d48
commit
db6bb13326
12 changed files with 804 additions and 1239 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue