stage6: port to coroutine system (WIP)
Closes #323 Mostly faithful to the original with a few changes. Needs a design iteration. Squashed commit of the following: commit17232ad797
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 07:14:12 2023 +0100 stage6: fix uninitialized variable commit46f7345d00
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 06:57:10 2023 +0100 stage6: fix warnings commit2c5ebc1f6c
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 06:49:07 2023 +0100 stage6: fix ricci grace period commitf43e1069d5
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 06:48:56 2023 +0100 stage6: formatting (ricci) commitd6c21a7e45
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 06:38:41 2023 +0100 stage6: remove dead code commit8cc8bc3358
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 06:38:27 2023 +0100 stage6: fix spell practice background commit555feafccf
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 01:59:43 2023 +0100 stage6: adjust elly's pre-ToE movement commitc0e71ccf92
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 01:55:58 2023 +0100 stage6: enable pre-ToE dialogue commit0902897b5a
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 01:24:49 2023 +0100 stage6: fix spell practice commitb4bd0c5902
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Mon Feb 6 01:24:33 2023 +0100 stage6: fix broglie issues commit115c90273f
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sun Feb 5 03:49:00 2023 +0100 stage6: formatting commitf0b564a290
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sun Feb 5 03:47:16 2023 +0100 stage6: fix a bunch of scythe-related issues commit8fcfb57080
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sun Feb 5 03:47:46 2023 +0100 stage6: define MAX_BARYON_PARTICLES commitff68532f9f
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sat Feb 4 07:00:50 2023 +0100 stage6: reset baryon target pos after attack commitbb49d60a79
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sat Feb 4 06:32:55 2023 +0100 stage6: more optimal draw order for baryon effect commit3230d378c1
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sat Feb 4 06:19:00 2023 +0100 stage6: port baryon background effect commitbf3df74eda
Author: Andrei Alexeyev <akari@taisei-project.org> Date: Sat Feb 4 04:35:49 2023 +0100 stage6: fix scythe and baryon visuals not spinning commit2492711a00
Author: Alice D <alice@starwitch.productions> Date: Sat Feb 12 18:38:55 2022 -0500 fix merge and compile issues, make stage end correctly commit4b04855932
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 08:40:47 2021 +0200 kepler: remove shadowing commit657345cce6
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 08:39:24 2021 +0200 move and rename scythe_nonspell_common task commit6a58fea718
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 08:34:33 2021 +0200 solve strange bug commit54df567170
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 08:21:36 2021 +0200 trigger weird bug in collision code by accident commit0bd3ceb9ac
Author: laochailan <laochailan@web.de> Date: Sat Sep 25 08:06:08 2021 +0200 scythe and baryon logic loose ends commitb4596a773e
Author: laochailan <laochailan@web.de> Date: Fri Sep 24 18:01:45 2021 +0200 toe port commitbc9137393c
Author: laochailan <laochailan@web.de> Date: Fri Sep 24 16:23:29 2021 +0200 wip toe port: pretty much all but the lasers commit60fd678d63
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 20:37:32 2021 +0200 wip toe port (only top level) commite14a35ed05
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 17:04:18 2021 +0200 forgotten port commit0cb56aee4c
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 14:34:51 2021 +0200 baryons_explode port commitc589a79bbf
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 09:04:01 2021 +0200 nonspell 5 port commitaac688112f
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 08:46:27 2021 +0200 ricci: remove obsolete commandments commit146d591b4c
Author: laochailan <laochailan@web.de> Date: Thu Sep 23 08:43:29 2021 +0200 lhc port commit2146ca342d
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 22:00:39 2021 +0200 broglie: implement Akari comments commit0222c67f60
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 20:24:58 2021 +0200 make ricci thicc commita04f122e99
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 20:12:13 2021 +0200 fix ricci timing and improve laser looks commitd3330ecd21
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 18:19:29 2021 +0200 wip: ricci but timing still wrong commit6c2129607a
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 16:53:42 2021 +0200 wip: ricci commit96d6e4499c
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 16:53:09 2021 +0200 make circle laser turn speed rad/frame commitd943e7ab88
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 16:52:27 2021 +0200 remove smoothreclamp commit7fbcd8fb43
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 12:17:36 2021 +0200 remove unused code commita6c8979107
Author: laochailan <laochailan@web.de> Date: Wed Sep 22 12:16:06 2021 +0200 modernize broglie sign commit278bd104d3
Author: laochailan <laochailan@web.de> Date: Wed Sep 1 19:54:00 2021 +0200 first baryon non commit20a7193de3
Author: laochailan <laochailan@web.de> Date: Tue Aug 31 22:03:54 2021 +0200 elly eigenstate commitc64ae7c792
Author: laochailan <laochailan@web.de> Date: Sat Aug 28 21:52:09 2021 +0200 elly until baryons spawn commit3d1a1eae9c
Author: laochailan <laochailan@web.de> Date: Sun Aug 22 14:54:02 2021 +0200 add double version of common_easing_animate commit16e6d51851
Author: laochailan <laochailan@web.de> Date: Sat Aug 7 21:52:58 2021 +0200 kepler sign + tweaks commitc460627e41
Author: laochailan <laochailan@web.de> Date: Thu Aug 5 20:31:15 2021 +0200 newton difficulty scaling commitbe97924a53
Author: laochailan <laochailan@web.de> Date: Wed Aug 4 22:06:30 2021 +0200 newton sign redesign commit20a4f3b4c7
Author: laochailan <laochailan@web.de> Date: Mon Aug 2 08:51:36 2021 +0200 first elly non wip commita2a5fb6ada
Author: laochailan <laochailan@web.de> Date: Mon Jul 26 20:23:09 2021 +0200 scythe wip commitae0eeec1ad
Author: laochailan <laochailan@web.de> Date: Mon Jul 26 18:16:59 2021 +0200 scythe wip commitf215d330d9
Author: laochailan <laochailan@web.de> Date: Fri Jul 23 22:18:51 2021 +0200 wip entity scythe commit66ccf18c63
Author: laochailan <laochailan@web.de> Date: Sun May 9 14:33:02 2021 +0200 wip spawn elly commitc947f0c3f9
Author: laochailan <laochailan@web.de> Date: Thu May 6 07:30:53 2021 +0200 modernize scythe mid commitbfae46ed24
Author: laochailan <laochailan@web.de> Date: Sun May 2 18:15:45 2021 +0200 more or less port flowermine fairy commit98370ed44b
Author: laochailan <laochailan@web.de> Date: Sun May 2 15:42:49 2021 +0200 modernized side fairy commitece28c70f0
Author: laochailan <laochailan@web.de> Date: Sun May 2 15:14:08 2021 +0200 modernize hacker fairy Co-authored-by: Andrei Alexeyev <akari@taisei-project.org> Co-authored-by: Alice D <alice@starwitch.productions>
This commit is contained in:
parent
b1e19f7069
commit
efa8e0b126
32 changed files with 2458 additions and 2319 deletions
|
@ -381,3 +381,14 @@ void common_rotate_velocity(MoveParams *move, real angle, int duration) {
|
|||
DEFINE_EXTERN_TASK(common_rotate_velocity) {
|
||||
common_rotate_velocity(ARGS.move, ARGS.angle, ARGS.duration);
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(common_easing_animated) {
|
||||
double from = *ARGS.value;
|
||||
double scale = ARGS.to - from;
|
||||
double ftime = ARGS.duration;
|
||||
|
||||
for(int t = 1; t <= ARGS.duration; t++) {
|
||||
YIELD;
|
||||
*ARGS.value = from + scale * ARGS.ease(t / ftime);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,3 +153,13 @@ DECLARE_EXTERN_TASK(
|
|||
int duration;
|
||||
}
|
||||
);
|
||||
|
||||
DECLARE_EXTERN_TASK(
|
||||
common_easing_animated,
|
||||
{
|
||||
double *value;
|
||||
double to;
|
||||
int duration;
|
||||
glm_ease_t ease;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -595,8 +595,7 @@ cmplx las_circle(Laser *l, float t) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// XXX: should turn speed be in rad/sec or rad/frame? currently rad/sec.
|
||||
double turn_speed = creal(l->args[0]) / 60;
|
||||
double turn_speed = creal(l->args[0]);
|
||||
double time_ofs = cimag(l->args[0]);
|
||||
double radius = creal(l->args[1]);
|
||||
|
||||
|
|
|
@ -79,9 +79,6 @@ TASK(stage6_bg_update) {
|
|||
cam->rot.v[2] = phi + cam_rot_offset;
|
||||
cam->pos[0] = r*cos(phi*M_TAU/360);
|
||||
cam->pos[1] = r*sin(phi*M_TAU/360);
|
||||
|
||||
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
@ -95,5 +92,12 @@ void stage6_bg_init_fullstage(void) {
|
|||
}
|
||||
|
||||
void stage6_bg_init_spellpractice(void) {
|
||||
stage6_bg_init_fullstage();
|
||||
Camera3D *cam = &stage_3d_context.cam;
|
||||
cam->pos[0] = -6;
|
||||
cam->pos[2] = 8;
|
||||
cam->rot.v[0] = 90;
|
||||
cam->rot.v[2] = 270;
|
||||
cam->fovy = STAGE3D_DEFAULT_FOVY*1.5;
|
||||
cam->far = 100;
|
||||
INVOKE_TASK(stage6_bg_3d_update);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "util/glm.h"
|
||||
#include "resource/model.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
|
||||
static Stage6DrawData *stage6_draw_data;
|
||||
|
||||
Stage6DrawData *stage6_get_draw_data(void) {
|
||||
|
@ -23,11 +21,10 @@ Stage6DrawData *stage6_get_draw_data(void) {
|
|||
}
|
||||
|
||||
void stage6_drawsys_init(void) {
|
||||
stage6_draw_data = calloc(1, sizeof(*stage6_draw_data));
|
||||
stage6_draw_data = ALLOC(typeof(*stage6_draw_data));
|
||||
// TODO: make this background slightly less horribly inefficient
|
||||
stage3d_init(&stage_3d_context, 128);
|
||||
|
||||
|
||||
for(int i = 0; i < NUM_STARS; i++) {
|
||||
vec3 p = { 0 };
|
||||
|
||||
|
@ -67,7 +64,7 @@ void stage6_drawsys_init(void) {
|
|||
|
||||
void stage6_drawsys_shutdown(void) {
|
||||
stage3d_shutdown(&stage_3d_context);
|
||||
free(stage6_draw_data);
|
||||
mem_free(stage6_draw_data);
|
||||
stage6_draw_data = NULL;
|
||||
}
|
||||
|
||||
|
@ -183,136 +180,6 @@ void stage6_draw(void) {
|
|||
stage3d_draw(&stage_3d_context, 100, ARRAY_SIZE(segs), segs);
|
||||
}
|
||||
|
||||
static void draw_baryon_connector(cmplx a, cmplx b) {
|
||||
Sprite *spr = res_sprite("stage6/baryon_connector");
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = spr,
|
||||
.pos = { creal(a + b) * 0.5, cimag(a + b) * 0.5 },
|
||||
.rotation.vector = { 0, 0, 1 },
|
||||
.rotation.angle = carg(a - b),
|
||||
.scale = { (cabs(a - b) - 70) / spr->w, 20 / spr->h },
|
||||
});
|
||||
}
|
||||
|
||||
void baryon(Enemy *e, int t, bool render) {
|
||||
if(render) {
|
||||
// the center piece draws the nodes; applying the postprocessing effect is easier this way.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_baryons(Enemy *bcenter, int t) {
|
||||
// r_color4(1, 1, 1, 0.8);
|
||||
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(bcenter->pos), cimag(bcenter->pos), 0);
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite = "stage6/baryon_center",
|
||||
.rotation.angle = DEG2RAD * 2 * t,
|
||||
.rotation.vector = { 0, 0, 1 },
|
||||
});
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite = "stage6/baryon",
|
||||
});
|
||||
|
||||
r_mat_mv_pop();
|
||||
|
||||
r_color4(1, 1, 1, 1);
|
||||
|
||||
Enemy *link0 = REF(creal(bcenter->args[1]));
|
||||
Enemy *link1 = REF(cimag(bcenter->args[1]));
|
||||
|
||||
if(link0 && link1) {
|
||||
draw_baryon_connector(bcenter->pos, link0->pos);
|
||||
draw_baryon_connector(bcenter->pos, link1->pos);
|
||||
}
|
||||
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == baryon) {
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.pos = { creal(e->pos), cimag(e->pos) },
|
||||
.sprite = "stage6/baryon",
|
||||
});
|
||||
|
||||
Enemy *n = REF(e->args[1]);
|
||||
|
||||
if(n != NULL) {
|
||||
draw_baryon_connector(e->pos, n->pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void baryon_center_draw(Enemy *bcenter, int t, bool render) {
|
||||
if(!render) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(config_get_int(CONFIG_POSTPROCESS) < 1) {
|
||||
draw_baryons(bcenter, t);
|
||||
return;
|
||||
}
|
||||
|
||||
stage_draw_begin_noshake();
|
||||
r_state_push();
|
||||
|
||||
r_shader("baryon_feedback");
|
||||
r_uniform_vec2("blur_resolution", 0.5*VIEWPORT_W, 0.5*VIEWPORT_H);
|
||||
r_uniform_float("hue_shift", 0);
|
||||
r_uniform_float("time", t/60.0);
|
||||
|
||||
r_framebuffer(stage6_draw_data->baryon.aux_fb);
|
||||
r_blend(BLEND_NONE);
|
||||
r_uniform_vec2("blur_direction", 1, 0);
|
||||
r_uniform_float("hue_shift", 0.01);
|
||||
r_color4(0.95, 0.88, 0.9, 0.5);
|
||||
|
||||
draw_framebuffer_tex(stage6_draw_data->baryon.fbpair.front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
fbpair_swap(&stage6_draw_data->baryon.fbpair);
|
||||
|
||||
r_framebuffer(stage6_draw_data->baryon.fbpair.back);
|
||||
r_uniform_vec2("blur_direction", 0, 1);
|
||||
r_color4(1, 1, 1, 1);
|
||||
draw_framebuffer_tex(stage6_draw_data->baryon.aux_fb, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
r_state_pop();
|
||||
stage_draw_end_noshake();
|
||||
|
||||
r_shader("sprite_default");
|
||||
draw_baryons(bcenter, t);
|
||||
|
||||
stage_draw_begin_noshake();
|
||||
|
||||
r_shader_standard();
|
||||
fbpair_swap(&stage6_draw_data->baryon.fbpair);
|
||||
r_color4(0.7, 0.7, 0.7, 0.7);
|
||||
draw_framebuffer_tex(stage6_draw_data->baryon.fbpair.front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
stage_draw_end_noshake();
|
||||
|
||||
r_color4(1, 1, 1, 1);
|
||||
r_framebuffer(stage6_draw_data->baryon.fbpair.front);
|
||||
r_shader("sprite_default");
|
||||
draw_baryons(bcenter, t);
|
||||
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == baryon) {
|
||||
cmplx p = e->pos; //+10*frand()*cexp(2.0*I*M_PI*frand());
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite = "part/myon",
|
||||
.color = RGBA(1, 0.2, 1.0, 0.7),
|
||||
.pos = { creal(p), cimag(p) },
|
||||
.rotation.angle = (creal(e->args[0]) - t) / 16.0, // frand()*M_PI*2,
|
||||
.scale.both = 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void elly_spellbg_classic(Boss *b, int t) {
|
||||
fill_viewport(0,0,0.7,"stage6/spellbg_classic");
|
||||
r_blend(BLEND_MOD);
|
||||
|
|
|
@ -55,9 +55,6 @@ void stage6_drawsys_init(void);
|
|||
void stage6_drawsys_shutdown(void);
|
||||
void stage6_draw(void);
|
||||
|
||||
void baryon_center_draw(Enemy*, int, bool);
|
||||
void baryon(Enemy*, int, bool);
|
||||
|
||||
extern ShaderRule stage6_bg_effects[];
|
||||
extern ShaderRule stage6_postprocess[];
|
||||
|
||||
|
|
|
@ -11,178 +11,413 @@
|
|||
#include "global.h"
|
||||
#include "elly.h"
|
||||
#include "draw.h"
|
||||
#include "util/glm.h"
|
||||
#include "spells/spells.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
|
||||
void scythe_common(Enemy *e, int t) {
|
||||
e->args[1] += cimag(e->args[1]);
|
||||
Boss* stage6_spawn_elly(cmplx pos) {
|
||||
Boss *b = create_boss("Elly", "elly", pos);
|
||||
boss_set_portrait(b, "elly", NULL, "normal");
|
||||
b->global_rule = elly_global_rule;
|
||||
return b;
|
||||
}
|
||||
|
||||
int wait_proj(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
if(t > creal(p->args[1])) {
|
||||
if(t == creal(p->args[1]) + 1) {
|
||||
play_sfx_ex("redirect", 4, false);
|
||||
spawn_projectile_highlight_effect(p);
|
||||
}
|
||||
|
||||
p->angle = carg(p->args[0]);
|
||||
p->pos += p->args[0];
|
||||
}
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
int scythe_mid(Enemy *e, int t) {
|
||||
TIMER(&t);
|
||||
cmplx n;
|
||||
|
||||
if(t < 0) {
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(creal(e->pos) > VIEWPORT_W + 100) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
e->pos += (6-global.diff-0.005*I*t)*e->args[0];
|
||||
|
||||
n = cexp(cimag(e->args[1])*I*t);
|
||||
FROM_TO_SND("shot1_loop",0,300,1) {}
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = e->pos + 80*n,
|
||||
.color = RGBA(0.2, 0.5-0.5*cimag(n), 0.5+0.5*creal(n), 0.0),
|
||||
.rule = wait_proj,
|
||||
.args = {
|
||||
global.diff*cexp(0.6*I)*n,
|
||||
100
|
||||
},
|
||||
);
|
||||
|
||||
if(global.diff > D_Normal && t&1) {
|
||||
Projectile *p = PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = e->pos + 80*n,
|
||||
.color = RGBA(0, 0.2, 0.5, 0.0),
|
||||
.rule = accelerated,
|
||||
.args = {
|
||||
n,
|
||||
0.01*global.diff*cexp(I*carg(global.plr.pos - e->pos - 80*n))
|
||||
},
|
||||
);
|
||||
|
||||
if(projectile_in_viewport(p)) {
|
||||
play_sfx("shot1");
|
||||
}
|
||||
}
|
||||
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void scythe_draw_trail(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
r_mat_mv_rotate(p->angle + (M_PI * 0.5), 0, 0, 1);
|
||||
r_mat_mv_scale(creal(p->args[1]), creal(p->args[1]), 1);
|
||||
float a = (1.0 - t/p->timeout) * (1.0 - cimag(p->args[1]));
|
||||
ProjDrawCore(p, RGBA(a, a, a, a));
|
||||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void scythe_draw(Enemy *e, int t, bool render) {
|
||||
if(render) {
|
||||
static void scythe_particles(EllyScythe *s, real oldangle) {
|
||||
if(s->scale == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PARTICLE(
|
||||
.sprite_ptr = get_sprite("stage6/scythe"),
|
||||
.pos = e->pos+I*6*sin(global.frames/25.0),
|
||||
.draw_rule = scythe_draw_trail,
|
||||
.timeout = 8,
|
||||
.args = { 0, e->args[2] },
|
||||
.angle = creal(e->args[1]) - M_PI/2,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.sprite_ptr = res_sprite("stage6/scythe"),
|
||||
.pos = s->pos+I*6*sin((global.frames - 0.5)/25.0),
|
||||
.draw_rule = pdraw_timeout_fade(0.75, 0),
|
||||
.timeout = 4,
|
||||
.angle = (s->angle + oldangle) * 0.5,
|
||||
.scale = s->scale,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
.layer = LAYER_PARTICLE_MID,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.sprite_ptr = res_sprite("stage6/scythe"),
|
||||
.pos = s->pos+I*6*sin(global.frames/25.0),
|
||||
.draw_rule = pdraw_timeout_fade(0.75, 0),
|
||||
.timeout = 4,
|
||||
.angle = s->angle,
|
||||
.scale = s->scale,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
.layer = LAYER_PARTICLE_MID,
|
||||
);
|
||||
|
||||
RNG_ARRAY(rand, 2);
|
||||
PARTICLE(
|
||||
.sprite = "smoothdot",
|
||||
.pos = e->pos+100*creal(e->args[2])*frand()*cexp(2.0*I*M_PI*frand()),
|
||||
.pos = s->pos + 100 * s->scale * vrng_real(rand[0]) * vrng_dir(rand[1]),
|
||||
.color = RGBA(1.0, 0.1, 1.0, 0.0),
|
||||
.draw_rule = GrowFade,
|
||||
.rule = linear,
|
||||
.draw_rule = pdraw_timeout_scalefade(0.4, 2, 1, 0),
|
||||
.timeout = 60,
|
||||
.args = { -I+1, -I+1 }, // XXX: what the fuck?
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
}
|
||||
|
||||
int scythe_infinity(Enemy *e, int t) {
|
||||
if(t < 0) {
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TIMER(&t);
|
||||
FROM_TO(0, 40, 1) {
|
||||
GO_TO(e, VIEWPORT_W/2+200.0*I, 0.01);
|
||||
e->args[2] = fmin(0.8, creal(e->args[2])+0.0003*t*t);
|
||||
e->args[1] = creal(e->args[1]) + I*fmin(0.2, cimag(e->args[1])+0.0001*t*t);
|
||||
}
|
||||
|
||||
FROM_TO_SND("shot1_loop",40, 3000, 1) {
|
||||
float w = fmin(0.15, 0.0001*(t-40));
|
||||
e->pos = VIEWPORT_W/2 + 200.0*I + 200*cos(w*(t-40)+M_PI/2.0) + I*80*sin(creal(e->args[0])*w*(t-40));
|
||||
|
||||
PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = e->pos+80*cexp(I*creal(e->args[1])),
|
||||
.color = RGB(cos(creal(e->args[1])), sin(creal(e->args[1])), cos(creal(e->args[1])+2.1)),
|
||||
.rule = asymptotic,
|
||||
.args = {
|
||||
(1+0.4*global.diff)*cexp(I*creal(e->args[1])),
|
||||
3 + 0.2 * global.diff
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
INLINE real normalize_angle(real a) {
|
||||
// [0 .. tau)
|
||||
return a - M_TAU * floorf(a / M_TAU);
|
||||
}
|
||||
|
||||
int scythe_reset(Enemy *e, int t) {
|
||||
if(t < 0) {
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
TASK(scythe_update, { BoxedEllyScythe scythe; }) {
|
||||
EllyScythe *scythe = TASK_BIND(ARGS.scythe);
|
||||
|
||||
if(t == 1)
|
||||
e->args[1] = fmod(creal(e->args[1]), 2*M_PI) + I*cimag(e->args[1]);
|
||||
real spin = 0;
|
||||
real oldangle;
|
||||
real return_speed_cap = 0;
|
||||
bool was_return_mode = false;
|
||||
|
||||
GO_TO(e, BOSS_DEFAULT_GO_POS, 0.05);
|
||||
e->args[2] = fmax(0.6, creal(e->args[2])-0.01*t);
|
||||
e->args[1] += (0.19-creal(e->args[1]))*0.05;
|
||||
e->args[1] = creal(e->args[1]) + I*0.9*cimag(e->args[1]);
|
||||
for(;;) {
|
||||
oldangle = scythe->angle;
|
||||
YIELD;
|
||||
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
approach_asymptotic_p(&spin, scythe->spin, 0.1, 1e-4);
|
||||
real spin_sign = sign(spin);
|
||||
real spin_abs = fabs(spin);
|
||||
|
||||
attr_returns_nonnull
|
||||
Enemy* find_scythe(void) {
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == scythe_draw) {
|
||||
return e;
|
||||
bool return_mode = scythe->spin == 0;
|
||||
|
||||
if(was_return_mode && !return_mode) {
|
||||
return_speed_cap = 0;
|
||||
}
|
||||
|
||||
if(spin_abs > return_speed_cap) {
|
||||
return_speed_cap = spin_abs;
|
||||
}
|
||||
|
||||
if(return_mode) {
|
||||
real return_target = normalize_angle(scythe->resting_angle);
|
||||
real scythe_angle = normalize_angle(scythe->angle);
|
||||
real delta;
|
||||
|
||||
if(spin_sign > 0) {
|
||||
if(return_target < scythe_angle) {
|
||||
return_target += M_TAU;
|
||||
}
|
||||
|
||||
delta = return_target - scythe_angle;
|
||||
} else {
|
||||
if(scythe_angle < return_target) {
|
||||
return_target -= M_TAU;
|
||||
}
|
||||
|
||||
delta = scythe_angle - return_target;
|
||||
}
|
||||
|
||||
spin_abs = fmin(return_speed_cap, delta * 0.1);
|
||||
}
|
||||
|
||||
was_return_mode = return_mode;
|
||||
scythe->angle += spin_sign * spin_abs;
|
||||
|
||||
move_update(&scythe->pos, &scythe->move);
|
||||
scythe_particles(scythe, oldangle);
|
||||
}
|
||||
}
|
||||
|
||||
static void stage6_init_elly_scythe(EllyScythe *scythe, cmplx pos) {
|
||||
scythe->pos = pos;
|
||||
scythe->scale = 0.7;
|
||||
scythe->resting_angle = -M_PI/2;
|
||||
scythe->angle = scythe->resting_angle;
|
||||
INVOKE_TASK(scythe_update, ENT_BOX(scythe));
|
||||
}
|
||||
|
||||
void stage6_despawn_elly_scythe(EllyScythe *scythe) {
|
||||
coevent_signal_once(&scythe->events.despawned);
|
||||
}
|
||||
|
||||
TASK(reset_scythe, { BoxedEllyScythe scythe; }) {
|
||||
EllyScythe *s = TASK_BIND(ARGS.scythe);
|
||||
s->resting_angle = -M_PI/2;
|
||||
s->move = move_towards(ELLY_DEFAULT_POS + ELLY_SCYTHE_RESTING_OFS, 0.1);
|
||||
s->spin = 0;
|
||||
}
|
||||
|
||||
Boss *stage6_elly_init_scythe_attack(ScytheAttackTaskArgs *args) {
|
||||
Boss *b = INIT_BOSS_ATTACK(&args->base);
|
||||
|
||||
if(ENT_UNBOX(args->scythe) == NULL) {
|
||||
args->scythe = ENT_BOX(stage6_host_elly_scythe(b->pos));
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
INVOKE_TASK_AFTER(
|
||||
&args->base.attack->events.finished,
|
||||
reset_scythe,
|
||||
args->scythe
|
||||
);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
EllyScythe *stage6_host_elly_scythe(cmplx pos) {
|
||||
EllyScythe *scythe = TASK_HOST_ENT(EllyScythe);
|
||||
TASK_HOST_EVENTS(scythe->events);
|
||||
stage6_init_elly_scythe(scythe, pos);
|
||||
return scythe;
|
||||
}
|
||||
|
||||
static void baryons_connector_particles(cmplx a, cmplx b, BoxedProjectileArray *particles) {
|
||||
Sprite *spr = res_sprite("stage6/baryon_connector");
|
||||
|
||||
cmplx connector_pos = (a + b)/2;
|
||||
real connector_angle = carg(a - b) + M_PI/2;
|
||||
cmplx connector_scale = (cabs(a - b) - 70) / spr->w + I * 20 / spr->h;
|
||||
ENT_ARRAY_ADD(particles, PARTICLE(
|
||||
.sprite_ptr = spr,
|
||||
.pos = connector_pos,
|
||||
.draw_rule = pdraw_timeout_fade(0.5, 0),
|
||||
.timeout = 2,
|
||||
.angle = connector_angle,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
.scale = connector_scale
|
||||
));
|
||||
}
|
||||
|
||||
static void baryons_particles(EllyBaryons *baryons, BoxedProjectileArray *particles) {
|
||||
if(baryons->scale == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ENT_ARRAY_ADD(particles, PARTICLE(
|
||||
.sprite_ptr = res_sprite("stage6/baryon_center"),
|
||||
.pos = baryons->center_pos,
|
||||
.draw_rule = pdraw_timeout_fade(0.75, 0),
|
||||
.timeout = 4,
|
||||
.angle = baryons->center_angle,
|
||||
.scale = baryons->scale,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
));
|
||||
|
||||
ENT_ARRAY_ADD(particles, PARTICLE(
|
||||
.sprite_ptr = res_sprite("stage6/baryon"),
|
||||
.pos = baryons->center_pos,
|
||||
.angle = M_TAU/12,
|
||||
.draw_rule = pdraw_timeout_fade(0.75, 0),
|
||||
.timeout = 4,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
));
|
||||
|
||||
|
||||
for(int i = 0; i < NUM_BARYONS; i++) {
|
||||
cmplx pos = baryons->poss[i];
|
||||
cmplx pos_next = baryons->poss[(i+1) % NUM_BARYONS];
|
||||
|
||||
ENT_ARRAY_ADD(particles, PARTICLE(
|
||||
.sprite_ptr = res_sprite("stage6/baryon"),
|
||||
.pos = pos,
|
||||
.draw_rule = pdraw_timeout_fade(0.75, 0),
|
||||
.timeout = 4,
|
||||
.scale = baryons->scale,
|
||||
.angle = baryons->angles[i]+M_TAU/12,
|
||||
.flags = PFLAG_REQUIREDPARTICLE | PFLAG_MANUALANGLE,
|
||||
));
|
||||
|
||||
baryons_connector_particles(pos, pos_next, particles);
|
||||
}
|
||||
|
||||
baryons_connector_particles(baryons->center_pos, baryons->poss[0], particles);
|
||||
baryons_connector_particles(baryons->center_pos, baryons->poss[3], particles);
|
||||
}
|
||||
|
||||
static void baryons_bg_feedback(Stage6DrawData *draw_data, int t) {
|
||||
stage_draw_begin_noshake();
|
||||
r_state_push();
|
||||
|
||||
r_shader("baryon_feedback");
|
||||
r_uniform_vec2("blur_resolution", 0.5*VIEWPORT_W, 0.5*VIEWPORT_H);
|
||||
r_uniform_float("hue_shift", 0);
|
||||
r_uniform_float("time", t/60.0);
|
||||
|
||||
r_framebuffer(draw_data->baryon.aux_fb);
|
||||
r_blend(BLEND_NONE);
|
||||
r_uniform_vec2("blur_direction", 1, 0);
|
||||
r_uniform_float("hue_shift", 0.01);
|
||||
r_color4(0.95, 0.88, 0.9, 0.5);
|
||||
|
||||
draw_framebuffer_tex(draw_data->baryon.fbpair.front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
fbpair_swap(&draw_data->baryon.fbpair);
|
||||
|
||||
r_framebuffer(draw_data->baryon.fbpair.back);
|
||||
r_uniform_vec2("blur_direction", 0, 1);
|
||||
r_color4(1, 1, 1, 1);
|
||||
draw_framebuffer_tex(draw_data->baryon.aux_fb, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
r_state_pop();
|
||||
stage_draw_end_noshake();
|
||||
}
|
||||
|
||||
static void baryons_bg_blend(Stage6DrawData *draw_data) {
|
||||
stage_draw_begin_noshake();
|
||||
r_state_push();
|
||||
|
||||
r_blend(BLEND_PREMUL_ALPHA);
|
||||
r_shader_standard();
|
||||
fbpair_swap(&draw_data->baryon.fbpair);
|
||||
r_color4(0.7, 0.7, 0.7, 0.7);
|
||||
draw_framebuffer_tex(draw_data->baryon.fbpair.front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
r_state_pop();
|
||||
stage_draw_end_noshake();
|
||||
}
|
||||
|
||||
static void baryons_bg_fill(Stage6DrawData *draw_data, int t, EllyBaryons *baryons, BoxedProjectileArray *particles) {
|
||||
if(!particles->size) {
|
||||
return;
|
||||
}
|
||||
|
||||
r_state_push();
|
||||
r_color4(1, 1, 1, 1);
|
||||
r_framebuffer(draw_data->baryon.fbpair.front);
|
||||
|
||||
ENT_ARRAY_FOREACH(particles, Projectile *p, {
|
||||
r_state_push();
|
||||
p->ent.draw_func(&p->entity_interface);
|
||||
r_state_pop();
|
||||
});
|
||||
|
||||
if(baryons) {
|
||||
ShaderProgram *shader = res_shader("sprite_default");
|
||||
Sprite *sprite = res_sprite("part/myon");
|
||||
|
||||
for(int i = 0; i < NUM_BARYONS; ++i) {
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = sprite,
|
||||
.shader_ptr = shader,
|
||||
.color = RGBA(1, 0.2, 1.0, 0.7),
|
||||
.pos.as_cmplx = baryons->poss[i], //+10*frand()*cexp(2.0*I*M_PI*frand());
|
||||
.rotation.angle = (i - t) / 16.0, // frand()*M_PI*2,
|
||||
.scale.both = 2,
|
||||
});
|
||||
}
|
||||
|
||||
r_flush_sprites();
|
||||
}
|
||||
|
||||
r_state_pop();
|
||||
}
|
||||
|
||||
TASK(baryons_particle_spawner, { BoxedEllyBaryons baryons; BoxedProjectileArray *particles; }) {
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
|
||||
for (;;) {
|
||||
baryons_particles(baryons, ARGS.particles);
|
||||
ENT_ARRAY_COMPACT(ARGS.particles);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(baryons_visuals, { BoxedEllyBaryons baryons; }) {
|
||||
DECLARE_ENT_ARRAY(Projectile, particles, MAX_BARYON_PARTICLES);
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
Stage6DrawData *draw_data = stage6_get_draw_data();
|
||||
|
||||
INVOKE_SUBTASK(baryons_particle_spawner, ARGS.baryons, &particles);
|
||||
|
||||
int timeout = 60;
|
||||
int endtime = timeout;
|
||||
|
||||
for(int t = 0; t < endtime; ++t) {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
EllyBaryons *baryons = ENT_UNBOX(ARGS.baryons);
|
||||
|
||||
if(baryons != NULL) {
|
||||
endtime = t + timeout;
|
||||
}
|
||||
|
||||
if(config_get_int(CONFIG_POSTPROCESS) < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
baryons_bg_fill(draw_data, t, baryons, &particles);
|
||||
baryons_bg_feedback(draw_data, t);
|
||||
baryons_bg_blend(draw_data);
|
||||
}
|
||||
}
|
||||
|
||||
TASK(baryons_update, { BoxedEllyBaryons baryons; }) {
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
|
||||
for (;;) {
|
||||
baryons->center_angle += 0.035;
|
||||
|
||||
for(int i = 0; i < NUM_BARYONS; i++) {
|
||||
cmplx d = (baryons->target_poss[i] - baryons->poss[i]);
|
||||
if(cabs2(d) > 0) {
|
||||
baryons->poss[i] += baryons->relaxation_rate * (d / sqrt(cabs(d)) + 0.01*d);
|
||||
}
|
||||
}
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(baryons_quick_intro, { BoxedEllyBaryons baryons; }) {
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
|
||||
int duration = 30;
|
||||
for(int t = 0; t < duration; t++) {
|
||||
baryons->scale = glm_ease_quad_in(t / (float) duration);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
cmplx stage6_elly_baryon_default_offset(int i) {
|
||||
return 150 * cdir(M_TAU / NUM_BARYONS * i);
|
||||
}
|
||||
|
||||
void stage6_init_elly_baryons(BoxedEllyBaryons baryons, BoxedBoss boss) {
|
||||
Boss *b = NOT_NULL(ENT_UNBOX(boss));
|
||||
EllyBaryons *eb = NOT_NULL(ENT_UNBOX(baryons));
|
||||
for(int i = 0; i < NUM_BARYONS; i++) {
|
||||
eb->target_poss[i] = b->pos + stage6_elly_baryon_default_offset(i);
|
||||
eb->poss[i] = b->pos;
|
||||
}
|
||||
eb->center_pos = b->pos;
|
||||
eb->scale = 0;
|
||||
eb->relaxation_rate = 0.5;
|
||||
INVOKE_TASK(baryons_update, baryons);
|
||||
INVOKE_TASK(baryons_visuals, baryons);
|
||||
}
|
||||
|
||||
TASK(reset_baryons, { BoxedBoss boss; BoxedEllyBaryons baryons; }) {
|
||||
auto baryons = TASK_BIND(ARGS.baryons);
|
||||
auto boss = NOT_NULL(ENT_UNBOX(ARGS.boss));
|
||||
|
||||
for(int i = 0; i < NUM_BARYONS; ++i) {
|
||||
baryons->target_poss[i] = boss->pos + stage6_elly_baryon_default_offset(i);
|
||||
}
|
||||
}
|
||||
|
||||
Boss *stage6_elly_init_baryons_attack(BaryonsAttackTaskArgs *args) {
|
||||
if(ENT_UNBOX(args->baryons) == NULL) {
|
||||
args->baryons = ENT_BOX(stage6_host_elly_baryons(args->base.boss));
|
||||
stage6_init_elly_baryons(args->baryons, args->base.boss);
|
||||
INVOKE_TASK(baryons_quick_intro, args->baryons);
|
||||
}
|
||||
|
||||
auto boss = INIT_BOSS_ATTACK(&args->base);
|
||||
|
||||
INVOKE_TASK_AFTER(
|
||||
&args->base.attack->events.finished,
|
||||
reset_baryons,
|
||||
ENT_BOX(boss), args->baryons
|
||||
);
|
||||
|
||||
return boss;
|
||||
}
|
||||
|
||||
EllyBaryons *stage6_host_elly_baryons(BoxedBoss boss) {
|
||||
EllyBaryons *baryons = TASK_HOST_ENT(EllyBaryons);
|
||||
TASK_HOST_EVENTS(baryons->events);
|
||||
return baryons;
|
||||
}
|
||||
|
||||
void elly_clap(Boss *b, int claptime) {
|
||||
|
@ -192,128 +427,3 @@ void elly_clap(Boss *b, int claptime) {
|
|||
aniplayer_queue(&b->ani, "main", 0);
|
||||
}
|
||||
|
||||
static int baryon_unfold(Enemy *baryon, int t) {
|
||||
if(t < 0)
|
||||
return 1; // not catching death for references! because there will be no death!
|
||||
|
||||
TIMER(&t);
|
||||
|
||||
int extent = 100;
|
||||
float timeout;
|
||||
|
||||
if(global.stage->type == STAGE_SPELL) {
|
||||
timeout = 92;
|
||||
} else {
|
||||
timeout = 142;
|
||||
}
|
||||
|
||||
FROM_TO(0, timeout, 1) {
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == baryon_center_draw) {
|
||||
float f = t / (float)timeout;
|
||||
float x = f;
|
||||
float g = sin(2 * M_PI * log(log(x + 1) + 1));
|
||||
float a = g * pow(1 - x, 2 * x);
|
||||
f = 1 - pow(1 - f, 3) + a;
|
||||
|
||||
baryon->pos = baryon->pos0 = e->pos + baryon->args[0] * f * extent;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int elly_baryon_center(Enemy *e, int t) {
|
||||
if(t == EVENT_DEATH) {
|
||||
free_ref(creal(e->args[1]));
|
||||
free_ref(cimag(e->args[1]));
|
||||
}
|
||||
|
||||
if(global.boss) {
|
||||
e->pos = global.boss->pos;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int scythe_explode(Enemy *e, int t) {
|
||||
if(t < 0) {
|
||||
scythe_common(e, t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(t < 50) {
|
||||
e->args[1] += 0.001*I*t;
|
||||
e->args[2] += 0.0015*t;
|
||||
}
|
||||
|
||||
if(t >= 50)
|
||||
e->args[2] -= 0.002*(t-50);
|
||||
|
||||
if(t == 100) {
|
||||
petal_explosion(100, e->pos);
|
||||
stage_shake_view(16);
|
||||
play_sfx("boom");
|
||||
|
||||
scythe_common(e, t);
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
scythe_common(e, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void elly_spawn_baryons(cmplx pos) {
|
||||
int i;
|
||||
Enemy *e, *last = NULL, *first = NULL, *middle = NULL;
|
||||
|
||||
for(i = 0; i < 6; i++) {
|
||||
e = create_enemy3c(pos, ENEMY_IMMUNE, baryon, baryon_unfold, 1.5*cexp(2.0*I*M_PI/6*i), i != 0 ? add_ref(last) : 0, i);
|
||||
e->ent.draw_layer = LAYER_BACKGROUND;
|
||||
|
||||
if(i == 0) {
|
||||
first = e;
|
||||
} else if(i == 3) {
|
||||
middle = e;
|
||||
}
|
||||
|
||||
last = e;
|
||||
}
|
||||
|
||||
first->args[1] = add_ref(last);
|
||||
e = create_enemy2c(pos, ENEMY_IMMUNE, baryon_center_draw, elly_baryon_center, 0, add_ref(first) + I*add_ref(middle));
|
||||
e->ent.draw_layer = LAYER_BACKGROUND;
|
||||
}
|
||||
|
||||
|
||||
void set_baryon_rule(EnemyLogicRule r) {
|
||||
Enemy *e;
|
||||
|
||||
for(e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == baryon) {
|
||||
e->birthtime = global.frames;
|
||||
e->logic_rule = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int baryon_reset(Enemy* baryon, int t) {
|
||||
if(t < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(Enemy *e = global.enemies.first; e; e = e->next) {
|
||||
if(e->visual_rule == baryon_center_draw) {
|
||||
cmplx targ_pos = baryon->pos0 - e->pos0 + e->pos;
|
||||
GO_TO(baryon, targ_pos, 0.1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
GO_TO(baryon, baryon->pos0, 0.1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,67 @@
|
|||
#define SYMMETRYTIME (HIGGSTIME+200)
|
||||
#define BREAKTIME (YUKAWATIME+400)
|
||||
|
||||
void scythe_common(Enemy*, int t);
|
||||
void scythe_draw(Enemy*, int, bool);
|
||||
int scythe_mid(Enemy*, int);
|
||||
int scythe_reset(Enemy*, int);
|
||||
int scythe_infinity(Enemy*, int);
|
||||
int scythe_explode(Enemy*, int);
|
||||
#define ELLY_DEFAULT_POS (BOSS_DEFAULT_GO_POS)
|
||||
#define ELLY_SCYTHE_RESTING_OFS (8)
|
||||
|
||||
Boss* stage6_spawn_elly(cmplx pos);
|
||||
|
||||
DEFINE_ENTITY_TYPE(EllyScythe, {
|
||||
cmplx pos;
|
||||
real angle;
|
||||
real spin;
|
||||
real resting_angle;
|
||||
|
||||
float scale;
|
||||
|
||||
MoveParams move;
|
||||
|
||||
COEVENTS_ARRAY(
|
||||
despawned
|
||||
) events;
|
||||
});
|
||||
|
||||
EllyScythe *stage6_host_elly_scythe(cmplx pos);
|
||||
void stage6_despawn_elly_scythe(EllyScythe *scythe);
|
||||
|
||||
DEFINE_TASK_INTERFACE_WITH_BASE(ScytheAttack, BossAttack, {
|
||||
BoxedEllyScythe scythe;
|
||||
});
|
||||
typedef TASK_IFACE_ARGS_TYPE(ScytheAttack) ScytheAttackTaskArgs;
|
||||
Boss *stage6_elly_init_scythe_attack(ScytheAttackTaskArgs *args);
|
||||
|
||||
|
||||
#define NUM_BARYONS 6
|
||||
|
||||
#define MAX_BARYON_PARTICLES 128
|
||||
|
||||
DEFINE_ENTITY_TYPE(EllyBaryons, {
|
||||
cmplx poss[NUM_BARYONS];
|
||||
cmplx target_poss[NUM_BARYONS];
|
||||
real relaxation_rate;
|
||||
|
||||
// angles are currently unused, broglie sign may use them. otherwise remove.
|
||||
real angles[NUM_BARYONS];
|
||||
|
||||
cmplx center_pos;
|
||||
float center_angle;
|
||||
float scale;
|
||||
|
||||
COEVENTS_ARRAY(
|
||||
despawned
|
||||
) events;
|
||||
});
|
||||
|
||||
EllyBaryons *stage6_host_elly_baryons(BoxedBoss boss);
|
||||
void stage6_init_elly_baryons(BoxedEllyBaryons baryons, BoxedBoss boss);
|
||||
|
||||
DEFINE_TASK_INTERFACE_WITH_BASE(BaryonsAttack, BossAttack, {
|
||||
BoxedEllyBaryons baryons;
|
||||
});
|
||||
|
||||
typedef TASK_IFACE_ARGS_TYPE(BaryonsAttack) BaryonsAttackTaskArgs;
|
||||
Boss *stage6_elly_init_baryons_attack(BaryonsAttackTaskArgs *args);
|
||||
|
||||
cmplx stage6_elly_baryon_default_offset(int i);
|
||||
|
||||
void elly_clap(Boss*, int);
|
||||
void elly_spawn_baryons(cmplx);
|
||||
|
||||
void set_baryon_rule(EnemyLogicRule);
|
||||
int baryon_reset(Enemy*, int);
|
||||
|
||||
int wait_proj(Projectile*, int);
|
||||
|
||||
Enemy* find_scythe(void);
|
||||
|
|
|
@ -10,4 +10,6 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#define ENTITIES_STAGE6(X, ...) \
|
||||
X(EllyScythe, __VA_ARGS__) \
|
||||
X(EllyBaryons, __VA_ARGS__) \
|
||||
END_OF_ENTITIES
|
||||
|
|
|
@ -10,6 +10,7 @@ stage6_src = files(
|
|||
'nonspells/boss_nonspell_3.c',
|
||||
'nonspells/boss_nonspell_4.c',
|
||||
'nonspells/boss_nonspell_5.c',
|
||||
'nonspells/boss_nonspell_6.c',
|
||||
'spells/lhc.c',
|
||||
'spells/toe.c',
|
||||
'spells/ricci.c',
|
||||
|
|
|
@ -9,25 +9,49 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "nonspells.h"
|
||||
#include "../elly.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
DEFINE_EXTERN_TASK(stage6_boss_nonspell_scythe_common) {
|
||||
EllyScythe *scythe = TASK_BIND(ARGS.scythe);
|
||||
|
||||
void elly_frequency(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
Enemy *scythe;
|
||||
cmplx center = ELLY_DEFAULT_POS;
|
||||
|
||||
AT(EVENT_BIRTH) {
|
||||
scythe = find_scythe();
|
||||
aniplayer_queue(&b->ani, "snipsnip", 0);
|
||||
scythe->birthtime = global.frames;
|
||||
scythe->logic_rule = scythe_infinity;
|
||||
scythe->args[0] = 2;
|
||||
}
|
||||
scythe->spin = 0.2;
|
||||
scythe->move = move_towards(center, 0.1);
|
||||
WAIT(40);
|
||||
scythe->move.retention = 0.9;
|
||||
|
||||
AT(EVENT_DEATH) {
|
||||
scythe = find_scythe();
|
||||
scythe->birthtime = global.frames;
|
||||
scythe->logic_rule = scythe_reset;
|
||||
scythe->args[0] = 0;
|
||||
for(int t = 0;; t++) {
|
||||
play_sfx_loop("shot1_loop");
|
||||
|
||||
real theta = 0.01 * t * (1 + 0.001 * t) + M_PI/2;
|
||||
scythe->pos = center + 200 * cos(theta) * (1 + sin(theta) * I) / (1 + pow(sin(theta), 2));
|
||||
|
||||
cmplx dir = cdir(scythe->angle);
|
||||
real vel = difficulty_value(1.4, 1.8, 2.2, 2.6);
|
||||
|
||||
cmplx color_dir = cdir(3 * theta);
|
||||
|
||||
if(t > 50) {
|
||||
PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = scythe->pos + 60 * dir * cdir(1.2),
|
||||
.color = RGB(creal(color_dir), cimag(color_dir), creal(color_dir * cdir(2.1))),
|
||||
.move = move_accelerated(0, 0.01 *vel * dir),
|
||||
);
|
||||
}
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(stage6_boss_nonspell_1) {
|
||||
STAGE_BOOKMARK(boss-non1);
|
||||
|
||||
stage6_elly_init_scythe_attack(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS.base);
|
||||
|
||||
INVOKE_SUBTASK(stage6_boss_nonspell_scythe_common, ARGS.scythe);
|
||||
|
||||
STALL;
|
||||
}
|
||||
|
|
|
@ -10,34 +10,27 @@
|
|||
|
||||
#include "nonspells.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
DEFINE_EXTERN_TASK(stage6_boss_nonspell_2) {
|
||||
STAGE_BOOKMARK(boss-non2);
|
||||
|
||||
void elly_frequency2(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
Boss *boss = stage6_elly_init_scythe_attack(&ARGS);
|
||||
BEGIN_BOSS_ATTACK(&ARGS.base);
|
||||
aniplayer_queue(&boss->ani, "snipsnip", 0);
|
||||
|
||||
AT(0) {
|
||||
Enemy *scythe = find_scythe();
|
||||
aniplayer_queue(&b->ani, "snipsnip", 0);
|
||||
scythe->birthtime = global.frames;
|
||||
scythe->logic_rule = scythe_infinity;
|
||||
scythe->args[0] = 4;
|
||||
}
|
||||
INVOKE_SUBTASK(stage6_boss_nonspell_scythe_common, ARGS.scythe);
|
||||
|
||||
AT(EVENT_DEATH) {
|
||||
Enemy *scythe = find_scythe();
|
||||
scythe->birthtime = global.frames;
|
||||
scythe->logic_rule = scythe_reset;
|
||||
scythe->args[0] = 0;
|
||||
}
|
||||
int interval = difficulty_value(3, 3, 2, 2);
|
||||
|
||||
for(int t = 1;; t++) {
|
||||
cmplx dir = sin(t * 0.35) * cdir(t*0.02);
|
||||
|
||||
FROM_TO_SND("shot1_loop",0, 2000, 3-global.diff/2) {
|
||||
cmplx n = sin(t*0.12*global.diff)*cexp(t*0.02*I*global.diff);
|
||||
PROJECTILE(
|
||||
.proto = pp_plainball,
|
||||
.pos = b->pos+80*n,
|
||||
.pos = boss->pos + 50 * dir,
|
||||
.color = RGB(0,0,0.7),
|
||||
.rule = asymptotic,
|
||||
.args = { 2*n/cabs(n), 3 }
|
||||
.move = move_asymptotic_simple(2*cnormalize(dir), 3)
|
||||
);
|
||||
|
||||
WAIT(interval);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,41 +11,59 @@
|
|||
#include "nonspells.h"
|
||||
#include "stagetext.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
#include "common_tasks.h"
|
||||
|
||||
void elly_paradigm_shift(Boss *b, int t) {
|
||||
if(global.stage->type == STAGE_SPELL) {
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.1)
|
||||
} else if(t == 0) {
|
||||
play_sfx("bossdeath");
|
||||
}
|
||||
TASK(scythe_explode, { BoxedEllyScythe scythe; }) {
|
||||
EllyScythe *scythe = TASK_BIND(ARGS.scythe);
|
||||
INVOKE_TASK(common_easing_animated, &scythe->angle, 1000, 100, glm_ease_quad_in);
|
||||
INVOKE_TASK(common_easing_animate, &scythe->scale, 1.7, 70, glm_ease_quad_inout);
|
||||
INVOKE_TASK_DELAYED(70, common_easing_animate, &scythe->scale, 0, 30, glm_ease_linear);
|
||||
|
||||
TIMER(&t);
|
||||
WAIT(100);
|
||||
petal_explosion(100, scythe->pos);
|
||||
play_sfx("boom");
|
||||
stage6_despawn_elly_scythe(scythe);
|
||||
}
|
||||
|
||||
AT(0) {
|
||||
Enemy *scythe = find_scythe();
|
||||
scythe->birthtime = global.frames;
|
||||
scythe->logic_rule = scythe_explode;
|
||||
elly_clap(b,150);
|
||||
}
|
||||
TASK(baryons_spawn, { BoxedBoss boss; BoxedEllyBaryons baryons; }) {
|
||||
stage6_init_elly_baryons(ARGS.baryons, ARGS.boss);
|
||||
int duration = 100;
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
INVOKE_SUBTASK(common_easing_animate, &baryons->scale, 1, duration, glm_ease_bounce_out);
|
||||
|
||||
if(global.stage->type != STAGE_SPELL) {
|
||||
AT(80) {
|
||||
audio_bgm_stop(0.5);
|
||||
real angle_offset = -5;
|
||||
|
||||
INVOKE_SUBTASK(common_easing_animated, &angle_offset, 0, duration, glm_ease_quad_out);
|
||||
|
||||
for(int t = 0; t < duration; t++) {
|
||||
Boss *b = NOT_NULL(ENT_UNBOX(ARGS.boss));
|
||||
for(int i = 0; i < NUM_BARYONS; i++) {
|
||||
real radius = 3*200.0/duration * clamp(t - duration/(real)NUM_BARYONS/2*i, 0, duration/3.0);
|
||||
baryons->target_poss[i] = b->pos + radius * cdir((1-2*(i&1)) * angle_offset + M_TAU/NUM_BARYONS*i);
|
||||
}
|
||||
}
|
||||
|
||||
AT(100) {
|
||||
if(global.stage->type != STAGE_SPELL) {
|
||||
stage_unlock_bgm("stage6boss_phase1");
|
||||
stage_start_bgm("stage6boss_phase2");
|
||||
stagetext_add("Paradigm Shift!", VIEWPORT_W/2+I*(VIEWPORT_H/2+64), ALIGN_CENTER, get_font("big"), RGB(1, 1, 1), 0, 120, 10, 30);
|
||||
}
|
||||
|
||||
elly_spawn_baryons(b->pos);
|
||||
}
|
||||
|
||||
AT(120) {
|
||||
stage_shake_view(200);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(stage6_boss_paradigm_shift) {
|
||||
STAGE_BOOKMARK(boss-baryons);
|
||||
Boss *boss = INIT_BOSS_ATTACK(&ARGS.base);
|
||||
BEGIN_BOSS_ATTACK(&ARGS.base);
|
||||
|
||||
play_sfx("bossdeath");
|
||||
|
||||
INVOKE_TASK(scythe_explode, ARGS.scythe);
|
||||
|
||||
elly_clap(boss, 150);
|
||||
|
||||
WAIT(80);
|
||||
audio_bgm_stop(0.5);
|
||||
WAIT(20);
|
||||
|
||||
stage_unlock_bgm("stage6boss_phase1");
|
||||
stage_start_bgm("stage6boss_phase2");
|
||||
stagetext_add("Paradigm Shift!", VIEWPORT_W/2.0 + I * (VIEWPORT_H/2.0+64), ALIGN_CENTER, res_font("big"), RGB(1, 1, 1), 0, 120, 10, 30);
|
||||
stage_shake_view(200);
|
||||
|
||||
INVOKE_TASK(baryons_spawn, ENT_BOX(boss), ARGS.baryons);
|
||||
}
|
||||
|
|
|
@ -10,87 +10,51 @@
|
|||
|
||||
#include "nonspells.h"
|
||||
|
||||
MODERNIZE_THIS_FILE_AND_REMOVE_ME
|
||||
|
||||
static int baryon_nattack(Enemy *e, int t) {
|
||||
if(t < 0)
|
||||
return 1;
|
||||
TASK(baryons_nonspell_movement, { BoxedEllyBaryons baryons; }) {
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
|
||||
TIMER(&t);
|
||||
|
||||
e->pos = global.boss->pos + (e->pos-global.boss->pos)*cexp(0.006*I);
|
||||
|
||||
FROM_TO_SND("shot1_loop",30, 10000, (7 - global.diff)) {
|
||||
float a = 0.2*_i + creal(e->args[2]) + 0.006*t;
|
||||
float ca = a + t/60.0f;
|
||||
PROJECTILE(
|
||||
.proto = pp_ball,
|
||||
.pos = e->pos+40*cexp(I*a),
|
||||
.color = RGB(cos(ca), sin(ca), cos(ca+2.1)),
|
||||
.rule = asymptotic,
|
||||
.args = {
|
||||
(1+0.2*global.diff)*cexp(I*a),
|
||||
3
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void elly_baryonattack(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
AT(0)
|
||||
set_baryon_rule(baryon_nattack);
|
||||
AT(EVENT_DEATH)
|
||||
set_baryon_rule(baryon_reset);
|
||||
}
|
||||
|
||||
void elly_baryonattack2(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
AT(0) {
|
||||
aniplayer_queue(&b->ani, "snipsnip", 0);
|
||||
set_baryon_rule(baryon_nattack);
|
||||
}
|
||||
AT(EVENT_DEATH)
|
||||
set_baryon_rule(baryon_reset);
|
||||
|
||||
FROM_TO(100, 100000, 200-5*global.diff) {
|
||||
play_sfx("shot_special1");
|
||||
|
||||
if(_i % 2) {
|
||||
int cnt = 5;
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
float a = M_PI/4;
|
||||
a = a * (i/(float)cnt) - a/2;
|
||||
cmplx n = cexp(I*(a+carg(global.plr.pos-b->pos)));
|
||||
|
||||
for(int j = 0; j < 3; ++j) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos,
|
||||
.color = RGB(0,0.2,0.9),
|
||||
.rule = asymptotic,
|
||||
.args = { n, 2 * j }
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int x, y;
|
||||
int w = 1+(global.diff > D_Normal);
|
||||
cmplx n = cexp(I*carg(global.plr.pos-b->pos));
|
||||
|
||||
for(x = -w; x <= w; x++) {
|
||||
for(y = -w; y <= w; y++) {
|
||||
PROJECTILE(
|
||||
.proto = pp_bigball,
|
||||
.pos = b->pos+25*(x+I*y)*n,
|
||||
.color = RGB(0,0.2,0.9),
|
||||
.rule = asymptotic,
|
||||
.args = { n, 3 },
|
||||
);
|
||||
}
|
||||
}
|
||||
for(int t = 0;; t++) {
|
||||
for(int i = 0; i < NUM_BARYONS; i++) {
|
||||
baryons->target_poss[i] = baryons->center_pos + 150 * cdir(M_TAU/6 * i + 0.006 * t);
|
||||
}
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFINE_EXTERN_TASK(stage6_boss_nonspell_baryons_common) {
|
||||
EllyBaryons *baryons = TASK_BIND(ARGS.baryons);
|
||||
INVOKE_SUBTASK(baryons_nonspell_movement, ARGS.baryons);
|
||||
|
||||
int interval = difficulty_value(6, 5, 4, 3);
|
||||
real speed = difficulty_value(1.2, 1.4, 1.6, 1.8);
|
||||
|
||||
WAIT(30) |