stage4: port to coroutine system (WIP)
Merges #285 Mostly functional, but needs a design iteration. Squashed commit of the following: commit792e817f77
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 05:46:51 2023 +0100 stage4: fix warning commiteefa6a5181
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 05:41:32 2023 +0100 stage4: vlad's army "fixes" commit7ac97455ef
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 05:40:48 2023 +0100 shader/sprite_negative: modulate color commit9a7121e329
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 04:44:13 2023 +0100 stage4: fix kurumi's boss nons to soft-reset position commita26c85c5bd
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 04:35:47 2023 +0100 stage4: use super fairy for supercard commit6453352555
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 04:33:20 2023 +0100 stage4: fix scythe commit9e0743573d
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 04:32:47 2023 +0100 stage4: use huge fairies for splashers commite36f3ab154
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Tue Jan 31 03:30:21 2023 +0100 stage4: formatting fixups commit11b2071790
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 11:55:00 2021 +0200 fix Alice D.’s comments and some other loose ends commit0e2bc7af1f
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 11:03:33 2021 +0200 stage4: remove unused constant commit1343a55141
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 11:02:54 2021 +0200 stage4: fix explosive_swirl crash commitc5e571707c
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 10:54:12 2021 +0200 update to latest task api commite7202f9492
Author: laochailan <laochailan@web.de> Date: Sun May 2 10:08:51 2021 +0200 attempt to fix scythe timing commit9abe4b4274
Author: laochailan <laochailan@web.de> Date: Sat May 1 21:04:23 2021 +0200 modernize vlads army except draw rules commitdaf2b18e3d
Author: laochailan <laochailan@web.de> Date: Sat May 1 08:53:28 2021 +0200 modernize vampiric vapor commit7a5ea6afc7
Author: laochailan <laochailan@web.de> Date: Sat May 1 07:42:43 2021 +0200 rename a function commite76888cafe
Author: laochailan <laochailan@web.de> Date: Fri Apr 30 21:10:20 2021 +0200 modernize blow the walls commitd3cf94f20a
Author: laochailan <laochailan@web.de> Date: Fri Apr 30 08:33:37 2021 +0200 remove the enemy from aniwall commit5604af5450
Author: laochailan <laochailan@web.de> Date: Thu Apr 29 21:41:30 2021 +0200 animate wall modernized todo: remove the enemy out of it commitd89c1d12b4
Author: laochailan <laochailan@web.de> Date: Wed Apr 28 20:55:57 2021 +0200 modernize red spike commitd963c50d2e
Author: laochailan <laochailan@web.de> Date: Wed Apr 28 19:35:07 2021 +0200 modernize gate_of_walachia commit98b592ab80
Author: laochailan <laochailan@web.de> Date: Tue Apr 27 18:47:41 2021 +0200 modernize kurumi nonspells commit109198fbb2
Author: laochailan <laochailan@web.de> Date: Mon Apr 26 17:47:47 2021 +0200 modernize scythe (as a fairy) commitb4b2b3d0e3
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 22:03:22 2021 +0200 modernize bigcircle_fairy commit4d1fa425b3
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 21:44:10 2021 +0200 modernize supercard fairy commit3214c1ab21
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 19:19:08 2021 +0200 modernize explosive_swirl commit8674f5d259
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 17:46:33 2021 +0200 modernize backfire_swirl commit645d56ac7d
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 14:32:38 2021 +0200 modernize cardbuster fairy commit2e641f6205
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 12:26:04 2021 +0200 modernize partcircle fairy commit46dd0dedca
Author: laochailan <laochailan@web.de> Date: Sun Apr 25 11:45:49 2021 +0200 modernize fodder_fairy commit706ca100bf
Author: Alice D <alice@starwitch.productions> Date: Thu Apr 15 20:10:42 2021 -0400 rebase commitf1cf5b2f6d
Author: Alice D <alice@starwitch.productions> Date: Sun Apr 11 17:17:32 2021 -0400 begin porting stage 4 - splasher fairies ported Co-authored-by: Andrei Alexeyev <akari@taisei-project.org> Co-authored-by: Alice D <alice@starwitch.productions>
This commit is contained in:
parent
e580657f5b
commit
93c68dbb0d
16 changed files with 1172 additions and 1244 deletions
|
@ -4,5 +4,5 @@
|
|||
|
||||
void spriteMain(out vec4 fragColor) {
|
||||
vec4 texel = texture(tex, texCoord);
|
||||
fragColor = vec4((1.0 - texel.rgb / max(0.01, texel.a)) * texel.a, 0);
|
||||
fragColor = color * vec4((1.0 - texel.rgb / max(0.01, texel.a)) * texel.a, 0);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,33 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
DEFINE_EXTERN_TASK(stage4_boss_nonspell_burst) {
|
||||
Boss *b = TASK_BIND(ARGS.boss);
|
||||
|
||||
int count = ARGS.count;
|
||||
for(int i = 0; i < ARGS.duration; i += WAIT(100)) {
|
||||
play_sfx("shot_special1");
|
||||
aniplayer_queue(&b->ani, "muda", 4);
|
||||
aniplayer_queue(&b->ani, "main", 0);
|
||||
|
||||
for(int j = 0; j < count; j++) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGBA(0.5, 0.0, 0.5, 0.0),
|
||||
.move = move_asymptotic_simple(cdir(M_TAU / count * j), 3),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(stage4_boss_nonspell_redirect) {
|
||||
Projectile *p = TASK_BIND(ARGS.proj);
|
||||
p->move = ARGS.new_move;
|
||||
p->color.b *= -1;
|
||||
play_sfx_ex("redirect", 10, false);
|
||||
spawn_projectile_highlight_effect(p);
|
||||
}
|
||||
|
||||
static void kurumi_global_rule(Boss *b, int time) {
|
||||
// FIXME: avoid running this every frame!
|
||||
|
@ -32,40 +58,19 @@ Boss *stage4_spawn_kurumi(cmplx pos) {
|
|||
return b;
|
||||
}
|
||||
|
||||
void kurumi_slave_visual(Enemy *e, int t, bool render) {
|
||||
if(render) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(t%2)) {
|
||||
cmplx offset = (frand()-0.5)*30;
|
||||
offset += (frand()-0.5)*20.0*I;
|
||||
DEFINE_EXTERN_TASK(stage4_boss_slave_visual) {
|
||||
for(;;) {
|
||||
PARTICLE(
|
||||
.sprite = "smoothdot",
|
||||
.pos = offset,
|
||||
.sprite = "stain",
|
||||
.pos = *ARGS.pos,
|
||||
.color = RGBA(0.3, 0.0, 0.0, 0.0),
|
||||
.draw_rule = Shrink,
|
||||
.rule = enemy_flare,
|
||||
.timeout = 50,
|
||||
.args = { (-50.0*I-offset)/50.0, add_ref(e) },
|
||||
.draw_rule = pdraw_timeout_fade(1, 0),
|
||||
.angle = rng_angle(),
|
||||
.scale = 0.4,
|
||||
.timeout = 30,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void kurumi_slave_static_visual(Enemy *e, int t, bool render) {
|
||||
if(render) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(e->args[1]) {
|
||||
PARTICLE(
|
||||
.sprite = "smoothdot",
|
||||
.pos = e->pos,
|
||||
.color = RGBA(1, 1, 1, 0),
|
||||
.draw_rule = Fade,
|
||||
.timeout = 30,
|
||||
);
|
||||
WAIT(ARGS.interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,27 +78,13 @@ void kurumi_spell_bg(Boss *b, int time) {
|
|||
float f = 0.5+0.5*sin(time/80.0);
|
||||
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(VIEWPORT_W/2, VIEWPORT_H/2,0);
|
||||
r_mat_mv_translate(VIEWPORT_W / 2.0, VIEWPORT_H / 2.0, 0);
|
||||
r_mat_mv_scale(0.6, 0.6, 1);
|
||||
r_color3(f, 1 - f, 1 - f);
|
||||
draw_sprite(0, 0, "stage4/kurumibg1");
|
||||
r_mat_mv_pop();
|
||||
r_color4(1, 1, 1, 0);
|
||||
fill_viewport(time/300.0, time/300.0, 0.5, "stage4/kurumibg2");
|
||||
fill_viewport(time / 300.0, time / 300.0, 0.5, "stage4/kurumibg2");
|
||||
r_color4(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
int kurumi_splitcard(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
if(t == creal(p->args[2])) {
|
||||
p->args[0] += p->args[3];
|
||||
p->color.b *= -1;
|
||||
play_sound_ex("redirect", 10, false);
|
||||
spawn_projectile_highlight_effect(p);
|
||||
}
|
||||
|
||||
return asymptotic(p, t);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,12 @@
|
|||
|
||||
#include "boss.h"
|
||||
|
||||
DECLARE_EXTERN_TASK(stage4_boss_nonspell_burst, { BoxedBoss boss; int duration; int count; });
|
||||
DECLARE_EXTERN_TASK(stage4_boss_nonspell_redirect, { BoxedProjectile proj; MoveParams new_move; });
|
||||
|
||||
DECLARE_EXTERN_TASK(stage4_boss_slave_visual, { cmplx *pos; int interval; });
|
||||
|
||||
Boss *stage4_spawn_kurumi(cmplx pos);
|
||||
void kurumi_slave_visual(Enemy *e, int t, bool render);
|
||||
void kurumi_slave_static_visual(Enemy *e, int t, bool render);
|
||||
int kurumi_splitcard(Projectile *p, int t);
|
||||
void kurumi_spell_bg(Boss*, int);
|
||||
|
|
|
@ -13,50 +13,44 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
DEFINE_EXTERN_TASK(stage4_boss_nonspell_1) {
|
||||
STAGE_BOOKMARK(boss-non1);
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
b->move = move_towards(VIEWPORT_W/2 + 200*I, 0.01);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
void kurumi_sbreaker(Boss *b, int time) {
|
||||
if(time < 0)
|
||||
return;
|
||||
int duration = difficulty_value(300, 350, 400, 450);
|
||||
int count = difficulty_value(12, 14, 16, 18);
|
||||
int redirect_time = 40;
|
||||
|
||||
int dur = 300+50*global.diff;
|
||||
int t = time % dur;
|
||||
int i;
|
||||
TIMER(&t);
|
||||
for(;;) {
|
||||
|
||||
int c = 10+global.diff*2;
|
||||
int kt = 40;
|
||||
|
||||
FROM_TO_SND("shot1_loop", 50, dur, 2+(global.diff < D_Hard)) {
|
||||
cmplx p = b->pos + 150*sin(_i/8.0)+100.0*I*cos(_i/15.0);
|
||||
|
||||
cmplx n = cexp(2.0*I*M_PI/c*_i);
|
||||
PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = p,
|
||||
.color = RGB(1.0, 0.0, 0.5),
|
||||
.rule = kurumi_splitcard,
|
||||
.args = {
|
||||
2*n,
|
||||
0,
|
||||
kt,
|
||||
1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-1.7*n
|
||||
}
|
||||
int rice_step = difficulty_value(3, 3, 2, 2);
|
||||
WAIT(50);
|
||||
INVOKE_SUBTASK_DELAYED(10, stage4_boss_nonspell_burst,
|
||||
.boss = ENT_BOX(b),
|
||||
.duration = duration-10,
|
||||
.count = 20
|
||||
);
|
||||
}
|
||||
|
||||
FROM_TO(60, dur, 100) {
|
||||
play_sfx("shot_special1");
|
||||
aniplayer_queue(&b->ani, "muda", 4);
|
||||
aniplayer_queue(&b->ani, "main", 0);
|
||||
for(int i = 0; i < duration/rice_step; i++, WAIT(rice_step)) {
|
||||
play_sfx_loop("shot1_loop");
|
||||
cmplx spawn_pos = b->pos + 150 * sin(i / 8.0) + I * 100.0 * cos(i / 15.0);
|
||||
|
||||
for(i = 0; i < 20; i++) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGBA(0.5, 0.0, 0.5, 0.0),
|
||||
.rule = asymptotic,
|
||||
.args = { cexp(2.0*I*M_PI/20.0*i), 3 },
|
||||
cmplx dir = cdir(M_TAU / count * i);
|
||||
|
||||
cmplx redirect_vel = 1.5 * cnormalize(global.plr.pos - spawn_pos - 2 * redirect_time * dir) + 0.3 * dir;
|
||||
|
||||
Projectile *p = PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = spawn_pos,
|
||||
.color = RGB(1.0, 0.0, 0.5),
|
||||
.move = move_linear(2 * dir),
|
||||
);
|
||||
|
||||
INVOKE_TASK_DELAYED(redirect_time, stage4_boss_nonspell_redirect,
|
||||
.proj = ENT_BOX(p),
|
||||
.new_move = move_asymptotic_simple(redirect_vel, 3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,53 +13,53 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
DEFINE_EXTERN_TASK(stage4_boss_nonspell_2) {
|
||||
STAGE_BOOKMARK(boss-non2);
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
b->move = move_towards(VIEWPORT_W/2 + 200*I, 0.01);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
void kurumi_breaker(Boss *b, int time) {
|
||||
int t = time % 400;
|
||||
int i;
|
||||
int duration = 350;
|
||||
|
||||
int c = 10+global.diff*2;
|
||||
int kt = 20;
|
||||
int count = difficulty_value(10, 12, 14, 16);
|
||||
int rice_step = difficulty_value(43, 36, 29, 22);
|
||||
int redirect_time = 20;
|
||||
|
||||
if(time < 0)
|
||||
return;
|
||||
int time = 0;
|
||||
for(;;) {
|
||||
WAIT(50);
|
||||
|
||||
GO_TO(b, VIEWPORT_W/2 + VIEWPORT_W/3*sin(time/220) + I*cimag(b->pos), 0.02);
|
||||
INVOKE_SUBTASK_DELAYED(10, stage4_boss_nonspell_burst,
|
||||
.boss = ENT_BOX(b),
|
||||
.duration = duration-10,
|
||||
.count = 20
|
||||
);
|
||||
|
||||
TIMER(&t);
|
||||
for(int i = 0; i < duration/rice_step; i++, WAIT(rice_step)) {
|
||||
cmplx boss_target = VIEWPORT_W / 2.0 + VIEWPORT_W / 3.0 * sin(time / 220.0) + I*cimag(b->pos);
|
||||
|
||||
FROM_TO_SND("shot1_loop", 50, 400, 50-7*global.diff) {
|
||||
cmplx p = b->pos + 150*sin(_i) + 100.0*I*cos(_i);
|
||||
b->move = move_towards(boss_target, 0.02);
|
||||
|
||||
for(i = 0; i < c; i++) {
|
||||
cmplx n = cexp(2.0*I*M_PI/c*i);
|
||||
PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = p,
|
||||
.color = RGB(1,0,0.5),
|
||||
.rule = kurumi_splitcard,
|
||||
.args = {
|
||||
3*n,
|
||||
0,
|
||||
kt,
|
||||
1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-2.6*n
|
||||
});
|
||||
}
|
||||
}
|
||||
play_sfx("shot1");
|
||||
cmplx spawn_pos = b->pos + 150 * sin(i) + 100.0 * I * cos(i);
|
||||
|
||||
FROM_TO(60, 400, 100) {
|
||||
play_sfx("shot_special1");
|
||||
aniplayer_queue(&b->ani,"muda",1);
|
||||
aniplayer_queue(&b->ani,"main",0);
|
||||
for(i = 0; i < 20; i++) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGBA(0.5, 0.0, 0.5, 0.0),
|
||||
.rule = asymptotic,
|
||||
.args = { cexp(2.0*I*M_PI/20.0*i), 3 },
|
||||
);
|
||||
for(int j = 0; j < count; j++) {
|
||||
cmplx dir = cdir(M_TAU / count * j);
|
||||
Projectile *p = PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = spawn_pos,
|
||||
.color = RGB(1,0,0.5),
|
||||
.move = move_linear(3 * dir)
|
||||
);
|
||||
cmplx redirect_vel = 1.5 * cnormalize(global.plr.pos - spawn_pos - 2 * redirect_time * dir) + 0.4 * dir;
|
||||
|
||||
INVOKE_TASK_DELAYED(redirect_time, stage4_boss_nonspell_redirect,
|
||||
.proj = ENT_BOX(p),
|
||||
.new_move = move_asymptotic_simple(redirect_vel, 3)
|
||||
);
|
||||
|
||||
}
|
||||
time++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
|
||||
#include "boss.h"
|
||||
|
||||
void kurumi_sbreaker(Boss *b, int time);
|
||||
void kurumi_breaker(Boss *b, int time);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage4_boss_nonspell_1, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(stage4_boss_nonspell_2, BossAttack);
|
||||
|
|
|
@ -9,104 +9,112 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "spells.h"
|
||||
#include "common_tasks.h"
|
||||
#include "../kurumi.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
typedef struct {
|
||||
cmplx pos;
|
||||
MoveParams move;
|
||||
} Mover; // make this global?
|
||||
|
||||
static int aniwall_bullet(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
TASK(mover_update, { Mover *m; }) {
|
||||
for(;;) {
|
||||
move_update(&ARGS.m->pos, &ARGS.m->move);
|
||||
YIELD;
|
||||
}
|
||||
|
||||
if(t > creal(p->args[1])) {
|
||||
if(global.diff > D_Normal) {
|
||||
tsrand_fill(2);
|
||||
p->args[0] += 0.1*(0.1-0.2*afrand(0) + 0.1*I-0.2*I*afrand(1))*(global.diff-2);
|
||||
p->args[0] += 0.002*cexp(I*carg(global.plr.pos - p->pos));
|
||||
}
|
||||
|
||||
p->pos += p->args[0];
|
||||
}
|
||||
|
||||
p->color.r = cimag(p->pos)/VIEWPORT_H;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static int aniwall_slave(Enemy *e, int t) {
|
||||
float re, im;
|
||||
|
||||
if(t < 0)
|
||||
return 1;
|
||||
TASK(kurumi_aniwall_bullet, { cmplx pos; MoveParams move; }) {
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGB(1,0,0),
|
||||
.move = ARGS.move,
|
||||
));
|
||||
|
||||
if(creal(e->pos) <= 0)
|
||||
e->pos = I*cimag(e->pos);
|
||||
if(creal(e->pos) >= VIEWPORT_W)
|
||||
e->pos = VIEWPORT_W + I*cimag(e->pos);
|
||||
if(cimag(e->pos) <= 0)
|
||||
e->pos = creal(e->pos);
|
||||
if(cimag(e->pos) >= VIEWPORT_H)
|
||||
e->pos = creal(e->pos) + I*VIEWPORT_H;
|
||||
for(;;) {
|
||||
p->color.r = cimag(p->pos)/VIEWPORT_H;
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
re = creal(e->pos);
|
||||
im = cimag(e->pos);
|
||||
TASK(kurumi_aniwall_slave_move, { Mover *m; cmplx direction; }) {
|
||||
|
||||
if(cabs(e->args[1]) <= 0.1) {
|
||||
if(re == 0 || re == VIEWPORT_W) {
|
||||
cmplx corners[] = {
|
||||
0,
|
||||
VIEWPORT_W,
|
||||
VIEWPORT_W + I * VIEWPORT_H,
|
||||
I * VIEWPORT_H,
|
||||
};
|
||||
|
||||
e->args[1] = 1;
|
||||
e->args[2] = 10.0*I;
|
||||
}
|
||||
real speed = 10;
|
||||
|
||||
e->pos += e->args[0]*t;
|
||||
int order;
|
||||
int next;
|
||||
if(creal(ARGS.direction) > 0) {
|
||||
next = 2;
|
||||
order = 1;
|
||||
} else {
|
||||
if((re <= 0) + (im <= 0) + (re >= VIEWPORT_W) + (im >= VIEWPORT_H) == 2) {
|
||||
float sign = 1;
|
||||
sign *= 1-2*(re > 0);
|
||||
sign *= 1-2*(im > 0);
|
||||
sign *= 1-2*(cimag(e->args[2]) == 0);
|
||||
e->args[2] *= sign*I;
|
||||
}
|
||||
|
||||
e->pos += e->args[2];
|
||||
|
||||
if(!(t % 7-global.diff-2*(global.diff > D_Normal))) {
|
||||
cmplx v = e->args[2]/cabs(e->args[2])*I*sign(creal(e->args[0]));
|
||||
if(cimag(v) > -0.1 || global.diff >= D_Normal) {
|
||||
play_sound("shot1");
|
||||
PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = e->pos+I*v*20*nfrand(),
|
||||
.color = RGB(1,0,0),
|
||||
.rule = aniwall_bullet,
|
||||
.args = { 1*v, 40 }
|
||||
);
|
||||
}
|
||||
}
|
||||
next = 3;
|
||||
order = -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
for(;; next = (next + order + ARRAY_SIZE(corners)) % ARRAY_SIZE(corners)) {
|
||||
cmplx d = corners[next] - ARGS.m->pos;
|
||||
ARGS.m->move = move_linear(speed * cnormalize(d));
|
||||
|
||||
void kurumi_aniwall(Boss *b, int time) {
|
||||
TIMER(&time);
|
||||
|
||||
AT(EVENT_DEATH) {
|
||||
enemy_kill_all(&global.enemies);
|
||||
}
|
||||
|
||||
GO_TO(b, VIEWPORT_W/2 + VIEWPORT_W/3*sin(time/200) + I*cimag(b->pos),0.03)
|
||||
|
||||
if(time < 0)
|
||||
return;
|
||||
|
||||
AT(0) {
|
||||
aniplayer_queue(&b->ani, "muda", 0);
|
||||
play_sound("laser1");
|
||||
create_lasercurve2c(b->pos, 50, 80, RGBA(1.0, 0.8, 0.8, 0.0), las_accel, 0, 0.2*cexp(0.4*I));
|
||||
create_enemy1c(b->pos, ENEMY_IMMUNE, kurumi_slave_static_visual, aniwall_slave, 0.2*cexp(0.4*I));
|
||||
create_lasercurve2c(b->pos, 50, 80, RGBA(1.0, 0.8, 0.8, 0.0), las_accel, 0, 0.2*cexp(I*M_PI - 0.4*I));
|
||||
create_enemy1c(b->pos, ENEMY_IMMUNE, kurumi_slave_static_visual, aniwall_slave, 0.2*cexp(I*M_PI - 0.4*I));
|
||||
int travel_time = cabs(d) / speed;
|
||||
WAIT(travel_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TASK(kurumi_aniwall_slave, { cmplx pos; cmplx direction; }) {
|
||||
Mover m = {
|
||||
.pos = ARGS.pos,
|
||||
.move = move_accelerated(0, 0.2*ARGS.direction)
|
||||
};
|
||||
INVOKE_SUBTASK(mover_update, &m);
|
||||
INVOKE_SUBTASK(stage4_boss_slave_visual, &m.pos, .interval = 1);
|
||||
|
||||
create_lasercurve2c(ARGS.pos, 50, 80, RGBA(1.0, 0.4, 0.4, 0.0), las_accel, 0, m.move.acceleration);
|
||||
|
||||
real target_edge = creal(ARGS.direction) > 0 ? VIEWPORT_W : 0;
|
||||
int impact_time = sqrt(2 * fabs(creal(ARGS.pos - target_edge) / creal(m.move.acceleration)));
|
||||
|
||||
WAIT(impact_time);
|
||||
|
||||
m.move = move_linear(10 * I * sign(cimag(ARGS.direction)));
|
||||
|
||||
INVOKE_SUBTASK(kurumi_aniwall_slave_move, &m, ARGS.direction);
|
||||
|
||||
int step = difficulty_value(6, 5, 2, 1);
|
||||
for(;;WAIT(step)) {
|
||||
cmplx vel = sign(creal(ARGS.direction)) * I * cnormalize(m.move.velocity);
|
||||
if(cimag(vel) > -0.1 || global.diff > D_Easy) {
|
||||
play_sfx("shot1");
|
||||
INVOKE_TASK(kurumi_aniwall_bullet,
|
||||
.pos = m.pos + I * vel * 20 * rng_sreal(),
|
||||
.move = move_linear(vel)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(kurumi_aniwall) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
b->move = move_towards((VIEWPORT_W + I * VIEWPORT_H) * 0.5, 0.0005);
|
||||
b->move.retention = cdir(0.01);
|
||||
|
||||
|
||||
aniplayer_queue(&b->ani, "muda", 0);
|
||||
play_sfx("laser1");
|
||||
INVOKE_SUBTASK(kurumi_aniwall_slave, .pos = b->pos, .direction = cdir(0.4));
|
||||
INVOKE_SUBTASK(kurumi_aniwall_slave, .pos = b->pos, .direction = cdir(M_PI - 0.4));
|
||||
STALL;
|
||||
}
|
||||
|
|
|
@ -9,105 +9,84 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "spells.h"
|
||||
#include "common_tasks.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
TASK(kurumi_blowwall_exploder, { cmplx pos; cmplx acceleration; }) {
|
||||
|
||||
static int blowwall_slave(Enemy *e, int t) {
|
||||
float re, im;
|
||||
cmplx pos = ARGS.pos;
|
||||
for(int t = 0; pos == cwclamp(pos, 0, VIEWPORT_W + I * VIEWPORT_H); t++, YIELD) {
|
||||
pos += ARGS.acceleration * t;
|
||||
}
|
||||
|
||||
if(t < 0)
|
||||
return 1;
|
||||
float f;
|
||||
ProjPrototype *type;
|
||||
|
||||
e->pos += e->args[0]*t;
|
||||
int count = difficulty_value(60, 100, 140, 180);
|
||||
|
||||
if(creal(e->pos) <= 0)
|
||||
e->pos = I*cimag(e->pos);
|
||||
if(creal(e->pos) >= VIEWPORT_W)
|
||||
e->pos = VIEWPORT_W + I*cimag(e->pos);
|
||||
if(cimag(e->pos) <= 0)
|
||||
e->pos = creal(e->pos);
|
||||
if(cimag(e->pos) >= VIEWPORT_H)
|
||||
e->pos = creal(e->pos) + I*VIEWPORT_H;
|
||||
for(int i = 0; i < count; i++) {
|
||||
f = rng_real();
|
||||
|
||||
re = creal(e->pos);
|
||||
im = cimag(e->pos);
|
||||
|
||||
if(re <= 0 || im <= 0 || re >= VIEWPORT_W || im >= VIEWPORT_H) {
|
||||
int i, c;
|
||||
float f;
|
||||
ProjPrototype *type;
|
||||
|
||||
c = 20 + global.diff*40;
|
||||
|
||||
for(i = 0; i < c; i++) {
|
||||
f = frand();
|
||||
|
||||
if(f < 0.3) {
|
||||
type = pp_soul;
|
||||
} else if(f < 0.6) {
|
||||
type = pp_bigball;
|
||||
} else {
|
||||
type = pp_plainball;
|
||||
}
|
||||
|
||||
PROJECTILE(
|
||||
.proto = type,
|
||||
.pos = e->pos,
|
||||
.color = RGBA(1.0, 0.1, 0.1, 0.0),
|
||||
.rule = asymptotic,
|
||||
.args = { (1+3*f)*cexp(2.0*I*M_PI*frand()), 4 },
|
||||
);
|
||||
if(f < 0.3) {
|
||||
type = pp_soul;
|
||||
} else if(f < 0.6) {
|
||||
type = pp_bigball;
|
||||
} else {
|
||||
type = pp_plainball;
|
||||
}
|
||||
|
||||
play_sound("shot_special1");
|
||||
return ACTION_DESTROY;
|
||||
PROJECTILE(
|
||||
.proto = type,
|
||||
.pos = pos,
|
||||
.color = RGBA(1.0, 0.1, 0.1, 0.0),
|
||||
.move = move_asymptotic_simple((1 + 3 * f) * rng_dir(), 4)
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
play_sfx("shot_special1");
|
||||
}
|
||||
|
||||
static void bwlaser(Boss *b, float arg, int slave) {
|
||||
create_lasercurve2c(b->pos, 50, 100, RGBA(1.0, 0.5+0.3*slave, 0.5+0.3*slave, 0.0), las_accel, 0, (0.1+0.1*slave)*cexp(I*arg));
|
||||
static void kurumi_blowwall_laser(Boss *b, cmplx direction, bool explode) {
|
||||
cmplx acceleration = 0.1 * (1 + explode) * direction;
|
||||
create_lasercurve2c(b->pos, 50, 100, RGBA(1.0, 0.3, 0.3, 0.0), las_accel, 0, acceleration);
|
||||
|
||||
if(slave) {
|
||||
play_sound("laser1");
|
||||
create_enemy1c(b->pos, ENEMY_IMMUNE, NULL, blowwall_slave, 0.2*cexp(I*arg));
|
||||
if(explode) {
|
||||
play_sfx("laser1");
|
||||
|
||||
INVOKE_SUBTASK(kurumi_blowwall_exploder, b->pos, acceleration);
|
||||
} else {
|
||||
// FIXME: needs a better sound
|
||||
play_sound("shot2");
|
||||
play_sound("shot_special1");
|
||||
play_sfx("shot_special1");
|
||||
play_sfx("redirect");
|
||||
}
|
||||
}
|
||||
|
||||
void kurumi_blowwall(Boss *b, int time) {
|
||||
int t = time % 600;
|
||||
TIMER(&t);
|
||||
DEFINE_EXTERN_TASK(kurumi_blowwall) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
if(time == EVENT_DEATH)
|
||||
enemy_kill_all(&global.enemies);
|
||||
b->move = move_towards(BOSS_DEFAULT_GO_POS, 0.04);
|
||||
|
||||
if(time < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.04)
|
||||
|
||||
AT(0) {
|
||||
INVOKE_SUBTASK(common_charge, b->pos, RGBA(1, 0.3, 0.2, 0), 50, .sound = COMMON_CHARGE_SOUNDS);
|
||||
for(;;) {
|
||||
aniplayer_queue(&b->ani,"muda",0);
|
||||
WAIT(50);
|
||||
kurumi_blowwall_laser(b, cdir(0.4), true);
|
||||
|
||||
WAIT(50);
|
||||
kurumi_blowwall_laser(b, cdir(M_PI-0.4), true);
|
||||
WAIT(100);
|
||||
for(int i = 0; i < 2; i++) {
|
||||
kurumi_blowwall_laser(b, cdir(-M_PI * rng_real()), true);
|
||||
WAIT(50);
|
||||
}
|
||||
play_sfx("laser1");
|
||||
for(int i = 0; i < 20; i++) {
|
||||
kurumi_blowwall_laser(b, cdir(M_PI / 10 * i), false);
|
||||
WAIT(10);
|
||||
}
|
||||
INVOKE_SUBTASK(common_charge, b->pos, RGBA(1, 0.3, 0.2, 0), 100, .sound = COMMON_CHARGE_SOUNDS);
|
||||
WAIT(50);
|
||||
}
|
||||
|
||||
AT(50)
|
||||
bwlaser(b, 0.4, 1);
|
||||
|
||||
AT(100)
|
||||
bwlaser(b, M_PI-0.4, 1);
|
||||
|
||||
FROM_TO(200, 300, 50)
|
||||
bwlaser(b, -M_PI*frand(), 1);
|
||||
|
||||
FROM_TO(300, 500, 10)
|
||||
bwlaser(b, M_PI/10*_i, 0);
|
||||
|
||||
}
|
||||
|
|
|
@ -8,67 +8,69 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "common_tasks.h"
|
||||
#include "spells.h"
|
||||
#include "../kurumi.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
TASK(kurumi_walachia_slave_move_turn, { cmplx *vel; int duration; cmplx offset; }) {
|
||||
for(int i = 0; i < ARGS.duration; i++, YIELD) {
|
||||
*ARGS.vel -= 0.02 * ARGS.offset;
|
||||
*ARGS.vel *= cdir(0.02);
|
||||
}
|
||||
}
|
||||
|
||||
static int kurumi_burstslave(Enemy *e, int t) {
|
||||
TIMER(&t);
|
||||
AT(EVENT_BIRTH)
|
||||
e->args[1] = e->args[0];
|
||||
AT(EVENT_DEATH) {
|
||||
free_ref(e->args[2]);
|
||||
return 1;
|
||||
TASK(kurumi_walachia_slave_move, { cmplx *pos; cmplx *vel; cmplx direction; }) {
|
||||
INVOKE_SUBTASK_DELAYED(40, kurumi_walachia_slave_move_turn, ARGS.vel, 60, ARGS.direction);
|
||||
|
||||
for(int i = 0;; i++, YIELD) {
|
||||
*ARGS.pos += 2 * *ARGS.vel * (sin(i / 10.0) + 1.5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(t == 600 || REF(e->args[2]) == NULL)
|
||||
return ACTION_DESTROY;
|
||||
TASK(kurumi_walachia_slave, { cmplx pos; cmplx direction; int lifetime; }) {
|
||||
cmplx pos = ARGS.pos;
|
||||
cmplx vel = ARGS.direction;
|
||||
|
||||
e->pos += 2*e->args[1]*(sin(t/10.0)+1.5);
|
||||
INVOKE_SUBTASK(stage4_boss_slave_visual, &pos, .interval = 1);
|
||||
|
||||
FROM_TO(0, 600, 18-2*global.diff) {
|
||||
float r = cimag(e->pos)/VIEWPORT_H;
|
||||
INVOKE_SUBTASK(kurumi_walachia_slave_move, &pos, &vel, ARGS.direction);
|
||||
|
||||
for(int i = 1; i >= -1; i -= 2) {
|
||||
int step = difficulty_value(16, 14, 12, 10);
|
||||
for(int i = 0; i < ARGS.lifetime; i += WAIT(step)) {
|
||||
float r = cimag(pos)/VIEWPORT_H;
|
||||
|
||||
for(int j = 1; j >= -1; j -= 2) {
|
||||
PROJECTILE(
|
||||
.proto = pp_wave,
|
||||
.pos = e->pos + i*10.0*I*e->args[0],
|
||||
.pos = pos + j * 10.0 * I * ARGS.direction,
|
||||
.color = RGB(r,0,0),
|
||||
.rule = accelerated,
|
||||
.args = { i*2.0*I*e->args[0], -0.01*e->args[1] }
|
||||
.move = move_accelerated(j * 2.0 * I * ARGS.direction, -0.01*vel)
|
||||
);
|
||||
}
|
||||
|
||||
play_sfx("shot1");
|
||||
}
|
||||
|
||||
FROM_TO(40, 100,1) {
|
||||
e->args[1] -= e->args[0]*0.02;
|
||||
e->args[1] *= cexp(0.02*I);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kurumi_slaveburst(Boss *b, int time) {
|
||||
int t = time % 400;
|
||||
TIMER(&t);
|
||||
DEFINE_EXTERN_TASK(kurumi_walachia) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
if(time == EVENT_DEATH)
|
||||
enemy_kill_all(&global.enemies);
|
||||
int slave_count = difficulty_value(5, 7, 9, 11);
|
||||
int duration = 400;
|
||||
|
||||
if(time < 0)
|
||||
return;
|
||||
|
||||
AT(0) {
|
||||
int i;
|
||||
int n = 3+2*global.diff;
|
||||
for(i = 0; i < n; i++) {
|
||||
create_enemy3c(b->pos, ENEMY_IMMUNE, kurumi_slave_visual, kurumi_burstslave, cexp(I*2*M_PI/n*i+0.2*I*time/500), 0, add_ref(b));
|
||||
for(int run = 0;; run++) {
|
||||
INVOKE_SUBTASK(common_charge, .pos = b->pos, .time = 40, .color = RGBA(1.0, 0, 0, 0));
|
||||
for(int i = 0; i < slave_count; i++) {
|
||||
INVOKE_SUBTASK(kurumi_walachia_slave,
|
||||
.pos = b->pos,
|
||||
.direction = cdir(M_TAU / slave_count * i + 0.16 * run),
|
||||
.lifetime = duration + 200);
|
||||
}
|
||||
WAIT(duration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,102 +9,116 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "spells.h"
|
||||
#include "common_tasks.h"
|
||||
#include "../kurumi.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
TASK(kurumi_redspike_slave, { cmplx pos; int direction; }) {
|
||||
cmplx pos = ARGS.pos;
|
||||
MoveParams move;
|
||||
|
||||
static int kurumi_spikeslave(Enemy *e, int t) {
|
||||
TIMER(&t);
|
||||
AT(EVENT_BIRTH)
|
||||
e->args[1] = e->args[0];
|
||||
AT(EVENT_DEATH) {
|
||||
free_ref(e->args[2]);
|
||||
return 1;
|
||||
}
|
||||
INVOKE_SUBTASK(common_move_ext, &pos, &move);
|
||||
INVOKE_SUBTASK(stage4_boss_slave_visual, &pos, .interval = 1);
|
||||
|
||||
move.velocity = ARGS.direction;
|
||||
move.retention = cdir(0.01 * ARGS.direction);
|
||||
|
||||
if(t == 300+50*global.diff || REF(e->args[2]) == NULL)
|
||||
return ACTION_DESTROY;
|
||||
int lifetime = difficulty_value(350, 400, 450, 500);
|
||||
int step = difficulty_value(16, 14, 12, 10);
|
||||
|
||||
e->pos += e->args[1];
|
||||
e->args[1] *= cexp(0.01*I*e->args[0]);
|
||||
for(int i = 0; i < lifetime/step; i++, WAIT(step)) {
|
||||
float r = cimag(pos)/VIEWPORT_H;
|
||||
|
||||
FROM_TO(0, 600, 18-2*global.diff) {
|
||||
float r = cimag(e->pos)/VIEWPORT_H;
|
||||
|
||||
for(int i = 1; i >= -1; i -= 2) {
|
||||
for(int d = 1; d >= -1; d -= 2) {
|
||||
PROJECTILE(
|
||||
.proto = pp_wave,
|
||||
.pos = e->pos + 10.0*I*e->args[0],
|
||||
.pos = pos + 10.0 * I * ARGS.direction,
|
||||
.color = RGB(r,0,0),
|
||||
.rule = linear,
|
||||
.args = { i*1.5*I*e->args[1] }
|
||||
.move = move_linear(d * 1.5 * I * move.velocity)
|
||||
);
|
||||
}
|
||||
|
||||
play_sound("shot1");
|
||||
play_sfx("shot1");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kurumi_redspike(Boss *b, int time) {
|
||||
int t = time % 500;
|
||||
|
||||
if(time == EVENT_DEATH)
|
||||
enemy_kill_all(&global.enemies);
|
||||
TASK(kurumi_redspike_spawn_slaves, { BoxedBoss boss; int interval; }) {
|
||||
Boss *b = TASK_BIND(ARGS.boss);
|
||||
|
||||
if(time < 0)
|
||||
return;
|
||||
|
||||
TIMER(&t);
|
||||
|
||||
FROM_TO(0, 500, 60) {
|
||||
create_enemy3c(b->pos, ENEMY_IMMUNE, kurumi_slave_visual, kurumi_spikeslave, 1-2*(_i&1), 0, add_ref(b));
|
||||
for(int i = 0;; i++) {
|
||||
INVOKE_SUBTASK(kurumi_redspike_slave, b->pos, 1 - 2 * (i&1));
|
||||
WAIT(ARGS.interval);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(kurumi_dryfountain) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
INVOKE_SUBTASK(kurumi_redspike_spawn_slaves, .boss = ENT_BOX(b), .interval = 60);
|
||||
|
||||
int step = difficulty_value(100, 50, 50, 50);
|
||||
int count = difficulty_value(8, 16, 16, 16);
|
||||
real speed = 3 * difficulty_value(1.1, 1.2, 1.2, 1.2);
|
||||
|
||||
for(;;) {
|
||||
for(int i = 0; i < count; i++) {
|
||||
cmplx vel = speed * cdir(M_TAU / count * i) * cnormalize(global.plr.pos-b->pos);
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGBA(1.0, 0.0, 0.0, 0.0),
|
||||
.move = move_asymptotic_simple(vel, 3)
|
||||
);
|
||||
}
|
||||
|
||||
play_sfx("shot_special1");
|
||||
WAIT(step);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TASK(kurumi_redspike_animate, { BoxedBoss boss; }) {
|
||||
Boss *b = TASK_BIND(ARGS.boss);
|
||||
WAIT(80);
|
||||
aniplayer_queue(&b->ani, "muda", 0);
|
||||
WAIT(420);
|
||||
aniplayer_queue(&b->ani, "main", 0);
|
||||
}
|
||||
|
||||
|
||||
DEFINE_EXTERN_TASK(kurumi_redspike) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
INVOKE_SUBTASK(kurumi_redspike_spawn_slaves, .boss = ENT_BOX(b), .interval = 60);
|
||||
for(;;) {
|
||||
INVOKE_SUBTASK(kurumi_redspike_animate, ENT_BOX(b));
|
||||
WAIT(80);
|
||||
|
||||
for(int rep = 0; rep < 2; rep++) {
|
||||
|
||||
int step = difficulty_value(4, 4, 4, 2);
|
||||
|
||||
for(int i = 0; i < 200; i += WAIT(step)) {
|
||||
RNG_ARRAY(rand, 2);
|
||||
cmplx offset = 100 * vrng_real(rand[0]) * vrng_dir(rand[1]);
|
||||
cmplx dir = cnormalize(global.plr.pos - b->pos - offset);
|
||||
|
||||
if(global.diff < D_Hard) {
|
||||
FROM_TO(0, 500, 150-50*global.diff) {
|
||||
int i;
|
||||
int n = global.diff*8;
|
||||
for(i = 0; i < n; i++) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGBA(1.0, 0.0, 0.0, 0.0),
|
||||
.rule = asymptotic,
|
||||
.args = {
|
||||
(1+0.1*(global.diff == D_Normal))*3*cexp(2.0*I*M_PI/n*i+I*carg(global.plr.pos-b->pos)),
|
||||
3
|
||||
},
|
||||
.proto = pp_rice,
|
||||
.pos = b->pos+offset,
|
||||
.color = RGBA(1, 0, 0, 0),
|
||||
.move = move_accelerated(-dir, 0.05 * dir),
|
||||
);
|
||||
|
||||
play_sfx_ex("warp",0,false);
|
||||
}
|
||||
|
||||
play_sound("shot_special1");
|
||||
}
|
||||
} else {
|
||||
AT(80) {
|
||||
aniplayer_queue(&b->ani, "muda", 0);
|
||||
}
|
||||
|
||||
AT(499) {
|
||||
aniplayer_queue(&b->ani, "main", 0);
|
||||
}
|
||||
|
||||
FROM_TO_INT(80, 500, 40,200,2+2*(global.diff == D_Hard)) {
|
||||
tsrand_fill(2);
|
||||
cmplx offset = 100*afrand(0)*cexp(2.0*I*M_PI*afrand(1));
|
||||
cmplx n = cexp(I*carg(global.plr.pos-b->pos-offset));
|
||||
PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = b->pos+offset,
|
||||
.color = RGBA(1, 0, 0, 0),
|
||||
.rule = accelerated,
|
||||
.args = { -1*n, 0.05*n },
|
||||
);
|
||||
play_sound_ex("warp",0,false);
|
||||
WAIT(40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
|
||||
#include "boss.h"
|
||||
|
||||
void kurumi_slaveburst(Boss*, int);
|
||||
void kurumi_redspike(Boss*, int);
|
||||
void kurumi_aniwall(Boss*, int);
|
||||
void kurumi_blowwall(Boss*, int);
|
||||
void kurumi_danmaku(Boss*, int);
|
||||
void kurumi_extra(Boss*, int);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_walachia, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_dryfountain, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_redspike, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_aniwall, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_blowwall, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_vampvape, BossAttack);
|
||||
DECLARE_EXTERN_TASK_WITH_INTERFACE(kurumi_vladsarmy, BossAttack);
|
||||
|
|
|
@ -9,139 +9,129 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "spells.h"
|
||||
#include "common_tasks.h"
|
||||
#include "../kurumi.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
|
||||
static Projectile *vapor_particle(cmplx pos, const Color *clr) {
|
||||
return PARTICLE(
|
||||
.sprite = "stain",
|
||||
.color = clr,
|
||||
.timeout = 60,
|
||||
.draw_rule = ScaleFade,
|
||||
.args = { 0, 0, 0.2 + 2.0*I },
|
||||
.draw_rule = pdraw_timeout_scalefade(0.2, 2.0, 0.6, 0),
|
||||
.pos = pos,
|
||||
.angle = M_PI*2*frand(),
|
||||
.angle = rng_angle(),
|
||||
);
|
||||
}
|
||||
|
||||
static int kdanmaku_proj(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
// XXX replace me by common_interpolate once merged
|
||||
TASK(interpolate, { float *clr; float target; float step; }) {
|
||||
for(;;) {
|
||||
fapproach_p(ARGS.clr, ARGS.target, ARGS.step);
|
||||
YIELD;
|
||||
}
|
||||
|
||||
int time = creal(p->args[0]);
|
||||
|
||||
if(t == time) {
|
||||
p->color = *RGBA(0.6, 0.3, 1.0, 0.0);
|
||||
projectile_set_prototype(p, pp_bullet);
|
||||
p->args[1] = (global.plr.pos - p->pos) * 0.001;
|
||||
|
||||
if(frand() < 0.5) {
|
||||
Projectile *v = vapor_particle(p->pos, color_mul_scalar(COLOR_COPY(&p->color), 0.5));
|
||||
|
||||
if(frand() < 0.5) {
|
||||
v->flags |= PFLAG_REQUIREDPARTICLE;
|
||||
}
|
||||
}
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.color = RGB(1, 1, 1),
|
||||
.timeout = 30,
|
||||
.draw_rule = ScaleFade,
|
||||
.args = { 0, 0, 3.0 },
|
||||
.pos = p->pos,
|
||||
);
|
||||
|
||||
play_sound("shot3");
|
||||
}
|
||||
|
||||
if(t > time && cabs(p->args[1]) < 2) {
|
||||
p->args[1] *= 1.02;
|
||||
fapproach_p(&p->color.a, 1, 0.025);
|
||||
}
|
||||
|
||||
p->pos += p->args[1];
|
||||
p->angle = carg(p->args[1]);
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static int kdanmaku_slave(Enemy *e, int t) {
|
||||
float re;
|
||||
TASK(kurumi_vampvape_proj, { int delay; cmplx pos; cmplx vel; }) {
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_thickrice,
|
||||
.pos = ARGS.pos,
|
||||
.color = RGBA(1.0, 0.5, 0.5, 0.0),
|
||||
.move = move_linear(ARGS.vel),
|
||||
.flags = PFLAG_NOSPAWNFLARE,
|
||||
));
|
||||
|
||||
if(t < 0)
|
||||
return 1;
|
||||
WAIT(ARGS.delay);
|
||||
|
||||
if(!e->args[1])
|
||||
e->pos += e->args[0]*t;
|
||||
else
|
||||
e->pos += 5.0*I;
|
||||
p->color = *RGBA(0.3, 0.8, 0.8, 0.0);
|
||||
projectile_set_prototype(p, pp_bullet);
|
||||
p->move = move_linear((global.plr.pos - p->pos) * 0.001);
|
||||
p->move.retention = 1.02;
|
||||
|
||||
if(creal(e->pos) <= 0)
|
||||
e->pos = I*cimag(e->pos);
|
||||
if(creal(e->pos) >= VIEWPORT_W)
|
||||
e->pos = VIEWPORT_W + I*cimag(e->pos);
|
||||
if(rng_chance(0.5)) {
|
||||
Projectile *v = vapor_particle(p->pos, color_mul_scalar(COLOR_COPY(&p->color), 0.3));
|
||||
|
||||
re = creal(e->pos);
|
||||
if(rng_chance(0.5)) {
|
||||
v->flags |= PFLAG_REQUIREDPARTICLE;
|
||||
}
|
||||
}
|
||||
|
||||
if(re <= 0 || re >= VIEWPORT_W)
|
||||
e->args[1] = 1;
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.color = RGB(1, 1, 1),
|
||||
.timeout = 30,
|
||||
.draw_rule = pdraw_timeout_scalefade(3.0, 0, 0.6, 0),
|
||||
.pos = p->pos,
|
||||
);
|
||||
|
||||
if(cimag(e->pos) >= VIEWPORT_H)
|
||||
return ACTION_DESTROY;
|
||||
play_sfx("shot3");
|
||||
|
||||
if(e->args[2] && e->args[1]) {
|
||||
int i, n = 3+imax(D_Normal,global.diff);
|
||||
float speed = 1.5+0.1*global.diff;
|
||||
INVOKE_SUBTASK(interpolate, &p->color.a, 1, 0.025);
|
||||
while(cabs(p->move.velocity) < 2) {
|
||||
YIELD;
|
||||
}
|
||||
p->move.retention = 1.0;
|
||||
}
|
||||
|
||||
TASK(kurumi_vampvape_slave, { cmplx pos; cmplx target; int time_offset; }) {
|
||||
cmplx direction = cnormalize(ARGS.target - ARGS.pos);
|
||||
cmplx acceleration = 0.2 * direction;
|
||||
|
||||
create_lasercurve2c(ARGS.pos, 50, 100, RGBA(1.0, 0.3, 0.3, 0.0), las_accel, 0, acceleration);
|
||||
|
||||
int travel_time = sqrt(2 * cabs(ARGS.target - ARGS.pos) / cabs(acceleration));
|
||||
WAIT(travel_time);
|
||||
real step = 5;
|
||||
int step_count = VIEWPORT_H / step;
|
||||
|
||||
for(int i = ARGS.time_offset; i < ARGS.time_offset + step_count; i++, YIELD) {
|
||||
real y = step * i;
|
||||
|
||||
int count = difficulty_value(3, 4, 5, 5);
|
||||
float speed = difficulty_value(0.5, 0.7, 0.9, 0.95);
|
||||
|
||||
for(int j = 0; j < count; j++) {
|
||||
cmplx p = VIEWPORT_W / (real)count * (j + psin(i * i * j * j + i * i)) + I * y;
|
||||
cmplx dir = cdir(M_TAU * sin(245 * i + j * j * 3501));
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
cmplx p = VIEWPORT_W/(float)n*(i+psin(t*t*i*i+t*t)) + I*cimag(e->pos);
|
||||
if(cabs(p-global.plr.pos) > 60) {
|
||||
PROJECTILE(
|
||||
.proto = pp_thickrice,
|
||||
.pos = p,
|
||||
.color = RGBA(1.0, 0.5, 0.5, 0.0),
|
||||
.rule = kdanmaku_proj,
|
||||
.args = { 160, speed*0.5*cexp(2.0*I*M_PI*sin(245*t+i*i*3501)) },
|
||||
.flags = PFLAG_NOSPAWNFLARE,
|
||||
);
|
||||
INVOKE_TASK(kurumi_vampvape_proj, 160, p, speed * dir);
|
||||
|
||||
if(frand() < 0.5) {
|
||||
vapor_particle(p, RGBA(0.5, 0.125 * frand(), 0.125 * frand(), 0.1));
|
||||
if(rng_chance(0.5)) {
|
||||
RNG_ARRAY(rand, 2);
|
||||
vapor_particle(p, RGBA(0.5, 0.125 * vrng_real(rand[0]), 0.125 * vrng_real(rand[1]), 0.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
play_sound_ex("redirect", 3, false);
|
||||
play_sfx_ex("redirect", 3, false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kurumi_danmaku(Boss *b, int time) {
|
||||
int t = time % 400;
|
||||
TIMER(&t);
|
||||
DEFINE_EXTERN_TASK(kurumi_vampvape) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
b->move = move_towards(BOSS_DEFAULT_GO_POS, 0.04);
|
||||
|
||||
if(time == EVENT_DEATH)
|
||||
enemy_kill_all(&global.enemies);
|
||||
if(time < 0)
|
||||
return;
|
||||
for(int t = 0;; t++) {
|
||||
INVOKE_SUBTASK(common_charge, b->pos, RGBA(1, 0.3, 0.2, 0), 50, .sound = COMMON_CHARGE_SOUNDS);
|
||||
WAIT(50);
|
||||
play_sfx("laser1");
|
||||
INVOKE_SUBTASK(kurumi_vampvape_slave,
|
||||
.pos = b->pos,
|
||||
.target = 0,
|
||||
.time_offset = t
|
||||
);
|
||||
INVOKE_SUBTASK(kurumi_vampvape_slave,
|
||||
.pos = b->pos,
|
||||
.target = VIEWPORT_W,
|
||||
.time_offset = 1.23*t
|
||||
);
|
||||
WAIT(210);
|
||||
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.04)
|
||||
|
||||
AT(260) {
|
||||
aniplayer_queue(&b->ani,"muda",4);
|
||||
aniplayer_queue(&b->ani,"main",0);
|
||||
}
|
||||
|
||||
AT(50) {
|
||||
play_sound("laser1");
|
||||
create_lasercurve2c(b->pos, 50, 100, RGBA(1.0, 0.8, 0.8, 0.0), las_accel, 0, 0.2*cexp(I*carg(-b->pos)));
|
||||
create_lasercurve2c(b->pos, 50, 100, RGBA(1.0, 0.8, 0.8, 0.0), las_accel, 0, 0.2*cexp(I*carg(VIEWPORT_W-b->pos)));
|
||||
create_enemy3c(b->pos, ENEMY_IMMUNE, kurumi_slave_static_visual, kdanmaku_slave, 0.2*cexp(I*carg(-b->pos)), 0, 1);
|
||||
create_enemy3c(b->pos, ENEMY_IMMUNE, kurumi_slave_static_visual, kdanmaku_slave, 0.2*cexp(I*carg(VIEWPORT_W-b->pos)), 0, 0);
|
||||
WAIT(140);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,143 +10,176 @@
|
|||
|
||||
#include "spells.h"
|
||||
#include "../kurumi.h"
|
||||
#include "enemy_classes.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
// TODO SUPER REDESIGN THIS, IT'S A MESS!
|
||||
|
||||
static void kurumi_extra_shield_pos(Enemy *e, int time) {
|
||||
double dst = 75 + 100 * fmax((60 - time) / 60.0, 0);
|
||||
double spd = cimag(e->args[0]) * fmin(time / 120.0, 1);
|
||||
e->args[0] += spd;
|
||||
e->pos = global.boss->pos + dst * cexp(I*creal(e->args[0]));
|
||||
static void kurumi_extra_shield_visual(Enemy *e, int time, bool render) {
|
||||
if(!render) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: something nicer here
|
||||
|
||||
float h = clampf(e->hp / e->spawn_hp, 0, 1);
|
||||
h *= h;
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.color = RGBA_MUL_ALPHA(
|
||||
1 + (1 - h), 0.3 + 0.7 * h, 0.2 + 0.8 * h,
|
||||
e->alpha * (1 + 1 - h)
|
||||
),
|
||||
.sprite = "enemy/swirl",
|
||||
.pos.as_cmplx = e->pos,
|
||||
.rotation.angle = time * -10 * DEG2RAD,
|
||||
.shader = "sprite_negative",
|
||||
});
|
||||
}
|
||||
|
||||
static bool kurumi_extra_shield_expire(Enemy *e, int time) {
|
||||
if(time > creal(e->args[1])) {
|
||||
e->hp = 0;
|
||||
return true;
|
||||
}
|
||||
static void draw_negative_fairy(Enemy *e, int t, Animation *ani) {
|
||||
const char *seqname = !e->moving ? "main" : (e->dir ? "left" : "right");
|
||||
Sprite *spr = animation_get_frame(ani, get_ani_sequence(ani, seqname), t);
|
||||
|
||||
return false;
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.shader = "sprite_negative",
|
||||
.color = RGBA_MUL_ALPHA(1, 1, 1, e->alpha),
|
||||
.sprite_ptr = spr,
|
||||
.pos.as_cmplx = e->pos,
|
||||
});
|
||||
}
|
||||
|
||||
static int kurumi_extra_dead_shield_proj(Projectile *p, int time) {
|
||||
if(time < 0) {
|
||||
return ACTION_ACK;
|
||||
static void kurumi_extra_fairy_visual(Enemy *e, int time, bool render) {
|
||||
if(render) {
|
||||
draw_negative_fairy(e, time, res_anim("enemy/fairy_blue"));
|
||||
}
|
||||
|
||||
p->color = *color_lerp(
|
||||
RGBA(2.0, 0.0, 0.0, 0.0),
|
||||
RGBA(0.2, 0.1, 0.5, 0.0),
|
||||
fmin(time / 60.0f, 1.0f));
|
||||
|
||||
return asymptotic(p, time);
|
||||
}
|
||||
|
||||
static int kurumi_extra_dead_shield(Enemy *e, int time) {
|
||||
if(time < 0) {
|
||||
return 1;
|
||||
static void kurumi_extra_bigfairy_visual(Enemy *e, int time, bool render) {
|
||||
if(render) {
|
||||
draw_negative_fairy(e, time, res_anim("enemy/superfairy"));
|
||||
}
|
||||
}
|
||||
|
||||
if(!(time % 6)) {
|
||||
// complex dir = cexp(I*(M_PI * 0.5 * nfrand() + carg(global.plr.pos - e->pos)));
|
||||
// complex dir = cexp(I*(carg(global.plr.pos - e->pos)));
|
||||
cmplx dir = cexp(I*creal(e->args[0]));
|
||||
PROJECTILE(
|
||||
.proto = pp_rice,
|
||||
.pos = e->pos,
|
||||
.rule = kurumi_extra_dead_shield_proj,
|
||||
.args = { 2*dir, 10 }
|
||||
);
|
||||
play_sound("shot1");
|
||||
TASK(kurumi_vladsarmy_shield_death_proj, { cmplx pos; MoveParams move; }) {
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = ARGS.pos,
|
||||
.move = ARGS.move
|
||||
));
|
||||
|
||||
int duration = 60;
|
||||
for(int i = 0; i < duration; i++, YIELD) {
|
||||
p->color = *color_lerp(
|
||||
RGBA(2.0, 0.0, 0.0, 0.0),
|
||||
RGBA(0.2, 0.1, 0.5, 0.0),
|
||||
i / (float) duration);
|
||||
}
|
||||
}
|
||||
|
||||
time += cimag(e->args[1]);
|
||||
TASK(kurumi_vladsarmy_shield_death, { BoxedEnemy enemy; }) {
|
||||
Enemy *e = ENT_UNBOX(ARGS.enemy);
|
||||
if(e == NULL || !(e->flags & EFLAG_IMPENETRABLE)) {
|
||||
return;
|
||||
}
|
||||
cmplx pos = e->pos;
|
||||
|
||||
kurumi_extra_shield_pos(e, time);
|
||||
play_sfx_ex("boon", 3, false);
|
||||
int shots = 5;
|
||||
int count = 10;
|
||||
|
||||
if(kurumi_extra_shield_expire(e, time)) {
|
||||
int cnt = 10;
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
cmplx dir = cexp(I*M_PI*2*i/(double)cnt);
|
||||
tsrand_fill(2);
|
||||
PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = e->pos,
|
||||
.rule = kurumi_extra_dead_shield_proj,
|
||||
.args = { 1.5 * (1 + afrand(0)) * dir, 4 + anfrand(1) },
|
||||
for(int i = 0; i < shots; i++) {
|
||||
|
||||
for(int j = 0; j < count; ++j) {
|
||||
cmplx dir = cdir(M_TAU/count * j);
|
||||
real speed = 2.5 * (1 + rng_real());
|
||||
|
||||
INVOKE_TASK(kurumi_vladsarmy_shield_death_proj,
|
||||
.pos = pos,
|
||||
.move = move_asymptotic_simple(speed * dir, -0.7)
|
||||
);
|
||||
}
|
||||
|
||||
play_sound("boom");
|
||||
WAIT(6);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kurumi_extra_shield(Enemy *e, int time) {
|
||||
if(time == EVENT_DEATH) {
|
||||
if(global.boss && !(global.gameover > 0) && !boss_is_dying(global.boss) && e->args[2] == 0) {
|
||||
create_enemy2c(e->pos, ENEMY_IMMUNE, kurumi_slave_visual, kurumi_extra_dead_shield, e->args[0], e->args[1]);
|
||||
}
|
||||
return 1;
|
||||
TASK(kurumi_vladsarmy_shield_manage, { BoxedEnemy enemy; BoxedBoss boss; real angle; int timeout; }) {
|
||||
Enemy *e = TASK_BIND(ARGS.enemy);
|
||||
|
||||
for(int i = 0; i < ARGS.timeout; i++, YIELD) {
|
||||
e->pos = NOT_NULL(ENT_UNBOX(ARGS.boss))->pos + 140 * cdir(ARGS.angle + 0.02 * i);
|
||||
}
|
||||
|
||||
if(time < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
e->args[1] = creal(e->args[1]) + time*I;
|
||||
|
||||
kurumi_extra_shield_pos(e, time);
|
||||
kurumi_extra_shield_expire(e, time);
|
||||
|
||||
return 1;
|
||||
e->flags &= ~EFLAG_IMPENETRABLE;
|
||||
enemy_kill(e);
|
||||
}
|
||||
|
||||
static int kurumi_extra_bigfairy1(Enemy *e, int time) {
|
||||
if(time < 0) {
|
||||
return 1;
|
||||
}
|
||||
TIMER(&time);
|
||||
TASK(kurumi_vladsarmy_shield, { BoxedBoss boss; real angle; }) {
|
||||
int hp = 1500;
|
||||
Boss *b = NOT_NULL(ENT_UNBOX(ARGS.boss));
|
||||
|
||||
int escapetime = 400+4000*(global.diff == D_Lunatic);
|
||||
if(time < escapetime) {
|
||||
GO_TO(e, e->args[0], 0.02);
|
||||
} else {
|
||||
GO_TO(e, e->args[0]-I*VIEWPORT_H,0.01)
|
||||
}
|
||||
Enemy *e = create_enemy2c(b->pos, hp, kurumi_extra_shield_visual, NULL, 0, 0);
|
||||
e->flags = EFLAG_IMPENETRABLE;
|
||||
|
||||
FROM_TO(50,escapetime,60) {
|
||||
int timeout = 800;
|
||||
INVOKE_SUBTASK_WHEN(&e->events.killed, kurumi_vladsarmy_shield_death, ENT_BOX(e));
|
||||
INVOKE_SUBTASK(kurumi_vladsarmy_shield_manage,
|
||||
.enemy=ENT_BOX(e),
|
||||
.boss = ARGS.boss,
|
||||
.angle = ARGS.angle,
|
||||
.timeout = timeout
|
||||
);
|
||||
STALL;
|
||||
}
|
||||
|
||||
TASK(kurumi_vladsarmy_bigfairy, { cmplx pos; cmplx target; }) {
|
||||
Enemy *e = TASK_BIND(espawn_big_fairy(ARGS.pos, ITEMS(.points = 2, .power = 1)));
|
||||
e->visual_rule = kurumi_extra_bigfairy_visual;
|
||||
|
||||
int escapetime = difficulty_value(400, 400, 400, 4000);
|
||||
|
||||
e->move = move_towards(ARGS.target, 0.02);
|
||||
|
||||
WAIT(50);
|
||||
for(int k = 0; k < escapetime; k += WAIT(60)) {
|
||||
int count = 5;
|
||||
cmplx phase = cexp(I*2*M_PI*frand());
|
||||
for(int i = 0; i < count; i++) {
|
||||
cmplx arg = cexp(I*2*M_PI*i/count);
|
||||
cmplx phase = rng_dir();
|
||||
for(int j = 0; j < count; j++) {
|
||||
cmplx dir = cdir(M_TAU * j / count);
|
||||
if(global.diff == D_Lunatic)
|
||||
arg *= phase;
|
||||
create_lasercurve2c(e->pos, 20, 200, RGBA(1.0, 0.3, 0.7, 0.0), las_accel, arg, 0.1*arg);
|
||||
dir *= phase;
|
||||
create_lasercurve2c(e->pos, 20, 200, RGBA(1.0, 0.3, 0.7, 0.0), las_accel, dir, 0.1 * dir);
|
||||
PROJECTILE(
|
||||
.proto = pp_bullet,
|
||||
.pos = e->pos,
|
||||
.color = RGB(1.0, 0.3, 0.7),
|
||||
.rule = accelerated,
|
||||
.args = { arg, 0.1*arg },
|
||||
.move = move_accelerated(dir, 0.1 * dir)
|
||||
);
|
||||
}
|
||||
|
||||
play_sound("laser1");
|
||||
// XXX make this sound enjoyable
|
||||
play_sfx_ex("laser1", 60, false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
e->move = move_towards(ARGS.target - I * VIEWPORT_H, 0.01);
|
||||
}
|
||||
|
||||
DEPRECATED_DRAW_RULE
|
||||
typedef struct DrainerState {
|
||||
Texture *texture;
|
||||
float alpha;
|
||||
cmplx target;
|
||||
} DrainerState;
|
||||
|
||||
static void kurumi_extra_drainer_draw(Projectile *p, int time, ProjDrawRuleArgs args) {
|
||||
// TODO: Make this use the sprite batcher?
|
||||
|
||||
DrainerState *drainer = args[0].as_ptr;
|
||||
|
||||
cmplx org = p->pos;
|
||||
cmplx targ = p->args[1];
|
||||
double a = 0.5 * creal(p->args[2]);
|
||||
Texture *tex = r_texture_get("part/sinewave");
|
||||
cmplx targ = drainer->target;
|
||||
float a = 0.5f * drainer->alpha;
|
||||
Texture *tex = drainer->texture;
|
||||
|
||||
r_shader_standard();
|
||||
|
||||
|
@ -160,131 +193,81 @@ static void kurumi_extra_drainer_draw(Projectile *p, int time, ProjDrawRuleArgs
|
|||
loop_tex_line_p(org, targ, 24, time * 0.003, tex);
|
||||
}
|
||||
|
||||
static int kurumi_extra_drainer(Projectile *p, int time) {
|
||||
if(time == EVENT_DEATH) {
|
||||
free_ref(p->args[0]);
|
||||
return ACTION_ACK;
|
||||
}
|
||||
TASK(kurumi_vladsarmy_drainer, { BoxedBoss boss; BoxedEnemy enemy; }) {
|
||||
DrainerState state = {
|
||||
.texture = res_texture("part/sinewave"),
|
||||
};
|
||||
|
||||
if(time < 0) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
Enemy *e = REF(p->args[0]);
|
||||
p->pos = global.boss->pos;
|
||||
|
||||
if(e) {
|
||||
p->args[1] = e->pos;
|
||||
p->args[2] = approach(p->args[2], 1, 0.5);
|
||||
|
||||
if(time > 40 && e->hp > 0) {
|
||||
// TODO: maybe add a special sound for this?
|
||||
|
||||
float drain = fmin(4, e->hp);
|
||||
ent_damage(&e->ent, &(DamageInfo) { .amount = drain });
|
||||
global.boss->current->hp = fmin(global.boss->current->maxhp, global.boss->current->hp + drain * 2);
|
||||
}
|
||||
} else {
|
||||
p->args[2] = approach(p->args[2], 0, 0.5);
|
||||
if(!creal(p->args[2])) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
}
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void kurumi_extra_create_drainer(Enemy *e) {
|
||||
PROJECTILE(
|
||||
Projectile *p = TASK_BIND(PROJECTILE(
|
||||
.size = 1+I,
|
||||
.pos = e->pos,
|
||||
.rule = kurumi_extra_drainer,
|
||||
.draw_rule = kurumi_extra_drainer_draw,
|
||||
.args = { add_ref(e) },
|
||||
.pos = NOT_NULL(ENT_UNBOX(ARGS.boss))->pos,
|
||||
.draw_rule = {
|
||||
.func = kurumi_extra_drainer_draw,
|
||||
.args[0].as_ptr = &state,
|
||||
},
|
||||
.shader = "sprite_default",
|
||||
.flags = PFLAG_NOCLEAR | PFLAG_NOCOLLISION,
|
||||
);
|
||||
.layer = LAYER_BOSS - 1,
|
||||
));
|
||||
|
||||
for(int i = 0;; i++, YIELD) {
|
||||
Enemy *e = ENT_UNBOX(ARGS.enemy);
|
||||
Boss *boss = ENT_UNBOX(ARGS.boss);
|
||||
|
||||
if(boss) {
|
||||
p->pos = boss->pos;
|
||||
}
|
||||
|
||||
if(e && boss) {
|
||||
state.target = e->pos;
|
||||
fapproach_asymptotic_p(&state.alpha, 1, 0.5, 1e-3);
|
||||
|
||||
if(i > 40 && e->hp > 0) {
|
||||
// TODO: maybe add a special sound for this?
|
||||
|
||||
float drain = fmin(4, e->hp);
|
||||
ent_damage(&e->ent, &(DamageInfo) { .amount = drain });
|
||||
boss->current->hp = fmin(boss->current->maxhp, boss->current->hp + drain * 2);
|
||||
}
|
||||
} else {
|
||||
fapproach_asymptotic_p(&state.alpha, 0, 0.5, 1e-3);
|
||||
if(!state.alpha) {
|
||||
kill_projectile(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kurumi_extra_swirl_visual(Enemy *e, int time, bool render) {
|
||||
if(!render) {
|
||||
// why the hell was this here?
|
||||
// Swirl(e, time, render);
|
||||
return;
|
||||
}
|
||||
TASK(kurumi_vladsarmy_fairy, { cmplx start_pos; cmplx target_pos; int attack_time; int chase_time; int attack_type; BoxedBoss boss; }){
|
||||
Enemy *e = TASK_BIND(espawn_fairy_blue(ARGS.start_pos, ITEMS(.points = 1)));
|
||||
e->visual_rule = kurumi_extra_fairy_visual;
|
||||
e->flags |= EFLAG_NO_AUTOKILL;
|
||||
|
||||
// FIXME: blend
|
||||
r_blend(BLEND_SUB);
|
||||
Swirl(e, time, render);
|
||||
r_blend(BLEND_PREMUL_ALPHA);
|
||||
}
|
||||
e->move = move_towards(ARGS.target_pos, 0.1);
|
||||
|
||||
static void kurumi_extra_fairy_visual(Enemy *e, int time, bool render) {
|
||||
if(!render) {
|
||||
Fairy(e, time, render);
|
||||
return;
|
||||
}
|
||||
|
||||
// r_blend(BLEND_ADD);
|
||||
r_shader("sprite_negative");
|
||||
Fairy(e, time, render);
|
||||
r_shader("sprite_default");
|
||||
// r_blend(BLEND_ALPHA);
|
||||
}
|
||||
|
||||
static void kurumi_extra_bigfairy_visual(Enemy *e, int time, bool render) {
|
||||
if(!render) {
|
||||
BigFairy(e, time, render);
|
||||
return;
|
||||
}
|
||||
|
||||
// r_blend(BLEND_ADD);
|
||||
r_shader("sprite_negative");
|
||||
BigFairy(e, time, render);
|
||||
r_shader("sprite_default");
|
||||
// r_blend(BLEND_ALPHA);
|
||||
}
|
||||
|
||||
static int kurumi_extra_fairy(Enemy *e, int t) {
|
||||
TIMER(&t);
|
||||
AT(EVENT_KILLED) {
|
||||
spawn_items(e->pos, ITEM_POINTS, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(e->flags & EFLAG_NO_AUTOKILL && t > 50)
|
||||
WAIT(50);
|
||||
e->flags &= ~EFLAG_NO_AUTOKILL;
|
||||
|
||||
if(creal(e->args[0]-e->pos) != 0)
|
||||
e->moving = true;
|
||||
e->dir = creal(e->args[0]-e->pos) < 0;
|
||||
WAIT(ARGS.attack_time-70);
|
||||
|
||||
FROM_TO(0,90,1) {
|
||||
GO_TO(e,e->args[0],0.1)
|
||||
}
|
||||
real speed = difficulty_value(2.0, 2.1, 2.2, 2.3);
|
||||
|
||||
/*FROM_TO(100, 200, 22-global.diff*3) {
|
||||
PROJECTILE("ball", e->pos, RGB(1, 0.3, 0.5), asymptotic, 2*cexp(I*M_PI*2*frand()), 3);
|
||||
}*/
|
||||
|
||||
int attacktime = creal(e->args[1]);
|
||||
int flytime = cimag(e->args[1]);
|
||||
FROM_TO_SND("shot1_loop", attacktime-20,attacktime+20,20) {
|
||||
cmplx vel = cexp(I*frand()*2*M_PI)*(2+0.1*(global.diff-D_Easy));
|
||||
if(e->args[2] == 0) { // attack type
|
||||
for(int k = 0; k <= 2; k++, WAIT(20)) {
|
||||
play_sfx_loop("shot1_loop");
|
||||
cmplx vel = speed * rng_dir();
|
||||
if(ARGS.attack_type == 0) {
|
||||
int corners = 5;
|
||||
double len = 50;
|
||||
int count = 5;
|
||||
real len = 50;
|
||||
int count = 4;
|
||||
for(int i = 0; i < corners; i++) {
|
||||
for(int j = 0; j < count; j++) {
|
||||
cmplx pos = len/2/tan(2*M_PI/corners)*I+(j/(double)count-0.5)*len;
|
||||
pos *= cexp(I*2*M_PI/corners*i);
|
||||
cmplx offset = 0.5 / tan(M_TAU / corners) * I + (j / (real)count - 0.5);
|
||||
offset *= len*cdir(M_TAU / corners * i);
|
||||
PROJECTILE(
|
||||
.proto = pp_flea,
|
||||
.pos = e->pos+pos,
|
||||
.pos = e->pos + offset,
|
||||
.color = RGB(1, 0.3, 0.5),
|
||||
.rule = linear,
|
||||
.args = { vel+0.1*I*pos/cabs(pos) }
|
||||
.move = move_linear(vel + 0.1 * cnormalize(offset)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -292,31 +275,26 @@ static int kurumi_extra_fairy(Enemy *e, int t) {
|
|||
int count = 30;
|
||||
double rad = 20;
|
||||
for(int j = 0; j < count; j++) {
|
||||
double x = (j/(double)count-0.5)*2*M_PI;
|
||||
cmplx pos = 0.5*cos(x)+sin(2*x) + (0.5*sin(x)+cos(2*x))*I;
|
||||
pos*=vel/cabs(vel);
|
||||
real x = M_TAU * (j / (real)count-0.5);
|
||||
cmplx pos = 0.5 * cos(x) + sin(2 * x) + (0.5 * sin(x) + cos( 2 * x))*I;
|
||||
pos *= cnormalize(vel);
|
||||
PROJECTILE(
|
||||
.proto = pp_flea,
|
||||
.pos = e->pos+rad*pos,
|
||||
.color = RGB(0.5, 0.3, 1),
|
||||
.rule = linear,
|
||||
.args = { vel+0.1*pos },
|
||||
.move = move_linear(vel + 0.1*pos),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
AT(attacktime) {
|
||||
e->args[0] = global.plr.pos-e->pos;
|
||||
kurumi_extra_create_drainer(e);
|
||||
play_sound("redirect");
|
||||
}
|
||||
FROM_TO(attacktime,attacktime+flytime,1) {
|
||||
e->pos += e->args[0]/flytime;
|
||||
}
|
||||
e->move = move_linear((global.plr.pos - e->pos) / ARGS.chase_time);
|
||||
INVOKE_TASK(kurumi_vladsarmy_drainer, ARGS.boss, ENT_BOX(e));
|
||||
play_sfx("redirect");
|
||||
|
||||
FROM_TO(attacktime,attacktime+flytime,20-global.diff*3) {
|
||||
int chase_drop_step = difficulty_value(17, 14, 11, 8);
|
||||
for(int i = 0; i < ARGS.chase_time / chase_drop_step; i++, WAIT(chase_drop_step)) {
|
||||
if(global.diff>D_Easy) {
|
||||
Color *clr = RGBA_MUL_ALPHA(0.1 + 0.07 * _i, 0.3, 1 - 0.05 * _i, 0.8);
|
||||
Color *clr = RGBA_MUL_ALPHA(0.1 + 0.07 * i, 0.3, 1 - 0.05 * i, 0.8);
|
||||
clr->a = 0;
|
||||
|
||||
PROJECTILE(
|
||||
|
@ -327,94 +305,95 @@ static int kurumi_extra_fairy(Enemy *e, int t) {
|
|||
);
|
||||
}
|
||||
}
|
||||
if(t > attacktime + flytime + 20 && global.boss) {
|
||||
GO_TO(e,global.boss->pos,0.04)
|
||||
}
|
||||
|
||||
return 1;
|
||||
e->move = move_towards(global.boss->pos, 0.04);
|
||||
}
|
||||
|
||||
void kurumi_extra(Boss *b, int time) {
|
||||
int length = 400;
|
||||
int t = time % length;
|
||||
int direction = (time/length)%2;
|
||||
DEFINE_EXTERN_TASK(kurumi_vladsarmy) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS);
|
||||
|
||||
int castlimit = b->current->maxhp * 0.05;
|
||||
int shieldlimit = b->current->maxhp * 0.1;
|
||||
cmplx startpos = VIEWPORT_W * 0.5 + VIEWPORT_H * 0.28 * I;
|
||||
|
||||
TIMER(&t);
|
||||
int prey_count = 20;
|
||||
int fairy_chase_time = difficulty_value(105, 100, 95, 90);
|
||||
|
||||
if(time == EVENT_DEATH) {
|
||||
enemy_kill_all(&global.enemies);
|
||||
return;
|
||||
}
|
||||
for(int run = 0;; run++) {
|
||||
b->move = move_towards(startpos, 0.01);
|
||||
int direction = run&1;
|
||||
|
||||
if(time < 120)
|
||||
GO_TO(b, VIEWPORT_W * 0.5 + VIEWPORT_H * 0.28 * I, 0.01)
|
||||
int castlimit = b->current->maxhp * 0.05;
|
||||
int shieldlimit = b->current->maxhp * 0.1;
|
||||
|
||||
if(t == 0 && b->current->hp >= shieldlimit) {
|
||||
int cnt = 12;
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
double a = M_PI * 2 * i / (double)cnt;
|
||||
int hp = 500;
|
||||
create_enemy2c(b->pos, hp, kurumi_extra_swirl_visual, kurumi_extra_shield, a + 0.05*I, 800);
|
||||
create_enemy2c(b->pos, hp, kurumi_extra_swirl_visual, kurumi_extra_shield, a - 0.05*I, 800);
|
||||
if(b->current->hp >= shieldlimit) {
|
||||
int shield_count = 12;
|
||||
for(int i = 0; i < shield_count; ++i) {
|
||||
real angle = M_TAU/shield_count * i;
|
||||
INVOKE_SUBTASK(kurumi_vladsarmy_shield, ENT_BOX(b), .angle = angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AT(90) {
|
||||
int cnt = 20;
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
WAIT(90);
|
||||
for(int i = 0; i < prey_count; i++) {
|
||||
b->current->hp -= 600;
|
||||
if(b->current->hp < castlimit)
|
||||
if(b->current->hp < castlimit) {
|
||||
b->current->hp = castlimit;
|
||||
tsrand_fill(2);
|
||||
cmplx pos = VIEWPORT_W/2*afrand(0)+I*afrand(1)*VIEWPORT_H*2/3;
|
||||
}
|
||||
|
||||
RNG_ARRAY(rand, 2);
|
||||
cmplx pos = vrng_real(rand[0]) * VIEWPORT_W / 2 + I * vrng_real(rand[1]) * VIEWPORT_H * 0.67;
|
||||
|
||||
if(direction)
|
||||
pos = VIEWPORT_W-creal(pos)+I*cimag(pos);
|
||||
// immune so they don’t get killed while they are still offscreen.
|
||||
Enemy *fairy = create_enemy3c(pos-300*(1-2*direction),500,kurumi_extra_fairy_visual,kurumi_extra_fairy,pos,100+20*i+100*(1.1-0.05*global.diff)*I,direction);
|
||||
fairy->flags |= EFLAG_NO_AUTOKILL;
|
||||
|
||||
INVOKE_SUBTASK(kurumi_vladsarmy_fairy,
|
||||
.start_pos = b->pos - 300 * (1 - 2 * direction),
|
||||
.target_pos = pos,
|
||||
.attack_time = 100 + 20 * i,
|
||||
.chase_time = fairy_chase_time,
|
||||
.attack_type = direction,
|
||||
.boss = ENT_BOX(b)
|
||||
);
|
||||
}
|
||||
|
||||
// XXX: maybe add a special sound for this?
|
||||
play_sound("shot_special1");
|
||||
}
|
||||
play_sfx("shot_special1");
|
||||
|
||||
cmplx sidepos = VIEWPORT_W * (0.5+0.3*(1-2*direction)) + VIEWPORT_H * 0.28 * I;
|
||||
FROM_TO(90,120,1) {
|
||||
GO_TO(b, sidepos,0.1)
|
||||
}
|
||||
cmplx sidepos = VIEWPORT_W * (0.5 + 0.3 * (1 - 2 * direction)) + VIEWPORT_H * 0.28 * I;
|
||||
b->move = move_towards(sidepos, 0.1);
|
||||
WAIT(100);
|
||||
b->move = move_towards(sidepos + 30 * I, 0.1);
|
||||
|
||||
FROM_TO(190,200,1) {
|
||||
GO_TO(b, sidepos+30*I,0.1)
|
||||
}
|
||||
|
||||
AT(190){
|
||||
aniplayer_queue_frames(&b->ani, "muda", 110);
|
||||
aniplayer_queue(&b->ani, "main", 0);
|
||||
}
|
||||
|
||||
FROM_TO(300,400,1) {
|
||||
GO_TO(b,VIEWPORT_W * 0.5 + VIEWPORT_H * 0.28 * I,0.1)
|
||||
}
|
||||
WAIT(110);
|
||||
|
||||
if(global.diff >= D_Hard) {
|
||||
AT(300) {
|
||||
double ofs = VIEWPORT_W * 0.5;
|
||||
b->move = move_towards(startpos, 0.1);
|
||||
|
||||
if(global.diff >= D_Hard) {
|
||||
double offset = VIEWPORT_W * 0.5;
|
||||
cmplx pos = 0.5 * VIEWPORT_W + I * (VIEWPORT_H - 100);
|
||||
cmplx targ = 0.5 *VIEWPORT_W + VIEWPORT_H * 0.3 * I;
|
||||
create_enemy1c(pos + ofs, 3300, kurumi_extra_bigfairy_visual, kurumi_extra_bigfairy1, targ + 0.8*ofs);
|
||||
create_enemy1c(pos - ofs, 3300, kurumi_extra_bigfairy_visual, kurumi_extra_bigfairy1, targ - 0.8*ofs);
|
||||
cmplx target = 0.5 * VIEWPORT_W + VIEWPORT_H * 0.3 * I;
|
||||
|
||||
INVOKE_SUBTASK(kurumi_vladsarmy_bigfairy,
|
||||
.pos = pos + offset,
|
||||
.target = target + 0.8*offset
|
||||
);
|
||||
INVOKE_SUBTASK(kurumi_vladsarmy_bigfairy,
|
||||
.pos = pos - offset,
|
||||
.target = target - 0.8*offset
|
||||
);
|
||||
}
|
||||
}
|
||||
if((t == length-20 && global.diff == D_Easy)|| b->current->hp < shieldlimit) {
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->logic_rule == kurumi_extra_shield) {
|
||||
e->args[2] = 1; // discharge extra shield
|
||||
e->hp = 0;
|
||||
continue;
|
||||
WAIT(100);
|
||||
|
||||
/*if((t == length-20 && global.diff == D_Easy)|| b->current->hp < shieldlimit) {
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->logic_rule == kurumi_extra_shield) {
|
||||
e->args[2] = 1; // discharge extra shield
|
||||
e->hp = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,40 +28,40 @@ struct stage4_spells_s stage4_spells = {
|
|||
.mid = {
|
||||
.gate_of_walachia = {
|
||||
{ 0, 1, 2, 3}, AT_Spellcard, "Bloodless “Gate of Walachia”", 50, 44000,
|
||||
kurumi_slaveburst, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_walachia)
|
||||
},
|
||||
.dry_fountain = {
|
||||
{ 4, 5, -1, -1}, AT_Spellcard, "Bloodless “Dry Fountain”", 50, 44000,
|
||||
kurumi_redspike, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_dryfountain)
|
||||
},
|
||||
.red_spike = {
|
||||
{-1, -1, 6, 7}, AT_Spellcard, "Bloodless “Red Spike”", 50, 46000,
|
||||
kurumi_redspike, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_redspike)
|
||||
},
|
||||
},
|
||||
|
||||
.boss = {
|
||||
.animate_wall = {
|
||||
{ 8, 9, -1, -1}, AT_Spellcard, "Limit “Animate Wall”", 60, 50000,
|
||||
kurumi_aniwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_aniwall),
|
||||
},
|
||||
.demon_wall = {
|
||||
{-1, -1, 10, 11}, AT_Spellcard, "Summoning “Demon Wall”", 60, 55000,
|
||||
kurumi_aniwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_aniwall)
|
||||
},
|
||||
.blow_the_walls = {
|
||||
{12, 13, 14, 15}, AT_Spellcard, "Power Sign “Blow the Walls”", 60, 55000,
|
||||
kurumi_blowwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_blowwall)
|
||||
},
|
||||
.bloody_danmaku = {
|
||||
{18, 19, 16, 17}, AT_Spellcard, "Predation “Vampiric Vapor”", 80, 60000,
|
||||
kurumi_danmaku, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_vampvape)
|
||||
},
|
||||
},
|
||||
|
||||
.extra.vlads_army = {
|
||||
{ 0, 1, 2, 3}, AT_ExtraSpell, "Blood Magic “Vlad’s Army”", 60, 50000,
|
||||
kurumi_extra, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4
|
||||
NULL, kurumi_spell_bg, BOSS_DEFAULT_GO_POS, 4, TASK_INDIRECT_INIT(BossAttack, kurumi_vladsarmy)
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -69,6 +69,8 @@ static void stage4_start(void) {
|
|||
stage4_drawsys_init();
|
||||
stage4_bg_init_fullstage();
|
||||
stage_start_bgm("stage4");
|
||||
stage_set_voltage_thresholds(170, 340, 660, 1040);
|
||||
INVOKE_TASK(stage4_timeline);
|
||||
}
|
||||
|
||||
static void stage4_spellpractice_start(void) {
|
||||
|
@ -136,7 +138,6 @@ StageProcs stage4_procs = {
|
|||
.preload = stage4_preload,
|
||||
.end = stage4_end,
|
||||
.draw = stage4_draw,
|
||||
.event = stage4_events,
|
||||
.shader_rules = stage4_bg_effects,
|
||||
.spellpractice_procs = &stage4_spell_procs,
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "boss.h"
|
||||
|
||||
void stage4_events(void);
|
||||
DECLARE_EXTERN_TASK(stage4_timeline);
|
||||
|
||||
#define STAGE4_MIDBOSS_TIME 3724
|
||||
#define STAGE4_MIDBOSS_MUSIC_TIME 2818
|
||||
|
|
Loading…
Reference in a new issue