remake Cirno's snowflake non
This commit is contained in:
parent
75e99fa5c8
commit
20a417da97
7 changed files with 118 additions and 65 deletions
|
@ -11,7 +11,7 @@
|
|||
#include "coroutine.h"
|
||||
#include "util.h"
|
||||
|
||||
#define CO_STACK_SIZE (64 * 1024)
|
||||
#define CO_STACK_SIZE (128 * 1024)
|
||||
|
||||
// #define TASK_DEBUG
|
||||
// #define EVT_DEBUG
|
||||
|
|
|
@ -274,4 +274,6 @@ INLINE void _ent_array_add_Entity(struct EntityInterface *ent, BoxedEntityArray
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
#define ENT_ARRAY_CLEAR(_array) ((_array)->size = 0)
|
||||
|
||||
#endif // IGUARD_entity_h
|
||||
|
|
10
src/move.c
10
src/move.c
|
@ -29,3 +29,13 @@ complex move_update(complex *restrict pos, MoveParams *restrict p) {
|
|||
|
||||
return v;
|
||||
}
|
||||
|
||||
complex move_update_multiple(uint times, complex *restrict pos, MoveParams *restrict p) {
|
||||
complex v = p->velocity;
|
||||
|
||||
while(times--) {
|
||||
move_update(pos, p);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef struct MoveParams {
|
|||
} MoveParams;
|
||||
|
||||
complex move_update(complex *restrict pos, MoveParams *restrict params);
|
||||
complex move_update_multiple(uint times, complex *restrict pos, MoveParams *restrict params);
|
||||
|
||||
INLINE MoveParams move_linear(complex vel) {
|
||||
return (MoveParams) { vel, 0, 1 };
|
||||
|
@ -50,4 +51,8 @@ INLINE MoveParams move_towards(complex target, complex attraction) {
|
|||
};
|
||||
}
|
||||
|
||||
INLINE MoveParams move_stop(complex retention) {
|
||||
return (MoveParams) { .retention = retention };
|
||||
}
|
||||
|
||||
#endif // IGUARD_move_h
|
||||
|
|
|
@ -709,6 +709,7 @@ static void bullet_highlight_draw(Projectile *p, int t) {
|
|||
|
||||
float opacity = pow(1 - timefactor, 2);
|
||||
opacity = min(1, 1.5 * opacity) * min(1, timefactor * 10);
|
||||
opacity *= 1 - p->shader_params.vector[0];
|
||||
|
||||
r_mat_tex_push();
|
||||
r_mat_tex_translate(0.5, 0.5, 0);
|
||||
|
|
|
@ -113,7 +113,7 @@ TASK_WITH_FINALIZER(test_enemy, {
|
|||
Projectile *p = PROJECTILE(
|
||||
.pos = e->pos,
|
||||
.proto = pp_rice,
|
||||
.color = RGBA(1.0, 0.0, i / (pcount - 1.0), 0.0),
|
||||
.color = RGBA(1.0, 0.2, i / (pcount - 1.0), 0.0),
|
||||
.move = move_asymptotic(aim * 4 * cdir(a + M_PI), aim * cdir(-a * 2), 0.9),
|
||||
.max_viewport_dist = 128,
|
||||
);
|
||||
|
|
|
@ -1623,89 +1623,124 @@ TASK(multiburst_fairies_1, NO_ARGS) {
|
|||
TASK_WITH_INTERFACE(midboss_intro, BossAttack) {
|
||||
Boss *boss = TASK_BIND(ARGS.boss);
|
||||
WAIT_EVENT(&ARGS.attack->events.started);
|
||||
boss->move = move_towards(VIEWPORT_W/2.0 + 100.0*I, 0.035);
|
||||
boss->move = move_towards(VIEWPORT_W/2.0 + 200.0*I, 0.035);
|
||||
}
|
||||
|
||||
#define SNOWFLAKE_ARMS 6
|
||||
|
||||
static int snowflake_bullet_limit(int size) {
|
||||
// >= number of bullets spawned per snowflake of this size
|
||||
return SNOWFLAKE_ARMS * 4 * size;
|
||||
}
|
||||
|
||||
TASK(cirno_snowflake_proj_twist, { BoxedProjectile p; }) {
|
||||
Projectile *p = TASK_BIND(ARGS.p);
|
||||
TASK(make_snowflake, { complex pos; MoveParams move; int size; double rot_angle; BoxedProjectileArray *array; }) {
|
||||
const double spacing = 12;
|
||||
const int split = 3;
|
||||
int t = 0;
|
||||
|
||||
play_sound_ex("redirect", 30, false);
|
||||
play_sound_ex("shot_special1", 30, false);
|
||||
color_lerp(&p->color, RGB(0.5, 0.5, 0.5), 0.5);
|
||||
spawn_projectile_highlight_effect(p);
|
||||
p->move.velocity = -cabs(p->move.velocity)*cdir(p->angle);
|
||||
for(int j = 0; j < ARGS.size; j++) {
|
||||
play_loop("shot1_loop");
|
||||
|
||||
for(int i = 0; i < SNOWFLAKE_ARMS; i++) {
|
||||
double ang = M_TAU / SNOWFLAKE_ARMS * i + ARGS.rot_angle;
|
||||
complex phase = cdir(ang);
|
||||
complex pos0 = ARGS.pos + spacing * j * phase;
|
||||
|
||||
Projectile *p;
|
||||
|
||||
for(int side = -1; side <= 1; side += 2) {
|
||||
p = PROJECTILE(
|
||||
.proto = pp_crystal,
|
||||
.pos = pos0 + side * 5 * I * phase,
|
||||
.color = RGB(0.0 + 0.05 * j, 0.1 + 0.1 * j, 0.9),
|
||||
.move = ARGS.move,
|
||||
.angle = ang + side * M_PI / 4,
|
||||
.max_viewport_dist = 128,
|
||||
.flags = PFLAG_MANUALANGLE,
|
||||
);
|
||||
move_update_multiple(t, &p->pos, &p->move);
|
||||
p->pos0 = p->prevpos = p->pos;
|
||||
ENT_ARRAY_ADD(ARGS.array, p);
|
||||
}
|
||||
|
||||
WAIT(1);
|
||||
++t;
|
||||
|
||||
if(j > split) {
|
||||
complex pos1 = ARGS.pos + spacing * split * phase;
|
||||
|
||||
for(int side = -1; side <= 1; side += 2) {
|
||||
complex phase2 = cdir(M_PI / 4 * side) * phase;
|
||||
complex pos2 = pos1 + (spacing * (j - split)) * phase2;
|
||||
|
||||
p = PROJECTILE(
|
||||
.proto = pp_crystal,
|
||||
.pos = pos2,
|
||||
.color = RGB(0.0, 0.3 * ARGS.size / 5, 1),
|
||||
.move = ARGS.move,
|
||||
.angle = ang + side * M_PI / 4,
|
||||
.max_viewport_dist = 128,
|
||||
.flags = PFLAG_MANUALANGLE,
|
||||
);
|
||||
move_update_multiple(t, &p->pos, &p->move);
|
||||
p->pos0 = p->prevpos = p->pos;
|
||||
ENT_ARRAY_ADD(ARGS.array, p);
|
||||
}
|
||||
|
||||
WAIT(1);
|
||||
++t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TASK_WITH_INTERFACE(icy_storm, BossAttack) {
|
||||
Boss *boss = TASK_BIND(ARGS.boss);
|
||||
Attack *a = ARGS.attack;
|
||||
|
||||
boss->move = move_towards(CMPLX(VIEWPORT_W/2, 200), 0.02);
|
||||
|
||||
CANCEL_TASK_WHEN(&a->events.finished, THIS_TASK);
|
||||
WAIT_EVENT(&a->events.started);
|
||||
|
||||
int interval = 70 - 8 * global.diff;
|
||||
boss->move = move_stop(0.8);
|
||||
|
||||
for(int run = 0;; run++) {
|
||||
complex vel = (1+0.125*global.diff)*cexp(I*fmod(200*run,M_PI));
|
||||
int c = 6;
|
||||
double dr = 15;
|
||||
int size = 5+3*sin(337*run);
|
||||
int flake_spawn_interval = difficulty_value(11, 10, 9, 8);
|
||||
int flakes_per_burst = difficulty_value(3, 5, 7, 9);
|
||||
double launch_speed = difficulty_value(5, 6.25, 6.875, 8.75);
|
||||
int size_base = 5;
|
||||
int size_oscillation = 3;
|
||||
int size_max = size_base + size_oscillation;
|
||||
int burst_interval = difficulty_value(120, 80, 80, 80);
|
||||
|
||||
int start_time = global.frames;
|
||||
int flakes_limit = flakes_per_burst * snowflake_bullet_limit(size_max);
|
||||
DECLARE_ENT_ARRAY(Projectile, snowflake_projs, flakes_limit);
|
||||
|
||||
for(int j = 0; j < size; j++) {
|
||||
WAIT(3);
|
||||
play_loop("shot1_loop");
|
||||
for(int i = 0; i < c; i++) {
|
||||
double ang = 2*M_PI/c*i+run*515;
|
||||
complex phase = cdir(ang);
|
||||
int t = global.frames-start_time;
|
||||
complex pos = boss->pos+vel*t+dr*j*phase;
|
||||
|
||||
int split_time = 200 - 20*global.diff - j*3;
|
||||
Projectile *p;
|
||||
|
||||
for(int side = -1; side <= 1; side += 2) {
|
||||
p = PROJECTILE(
|
||||
.proto = pp_crystal,
|
||||
.pos = pos+side*6*I*phase,
|
||||
.color = RGB(0.0, 0.1 + 0.1 * size / 5, 0.8),
|
||||
.move = move_linear(vel),
|
||||
.angle = ang+side*M_PI/4,
|
||||
.max_viewport_dist = 64,
|
||||
.flags = PFLAG_MANUALANGLE,
|
||||
);
|
||||
INVOKE_TASK_DELAYED(split_time, cirno_snowflake_proj_twist, ENT_BOX(p));
|
||||
}
|
||||
|
||||
int split = 3;
|
||||
|
||||
if(j > split) {
|
||||
complex pos0 = boss->pos+vel*t+dr*split*phase;
|
||||
|
||||
for(int side = -1; side <= 1; side+=2) {
|
||||
complex phase2 = cdir(M_PI/4*side)*phase;
|
||||
complex pos2 = pos0+(dr*(j-split))*phase2;
|
||||
|
||||
p = PROJECTILE(
|
||||
.proto = pp_crystal,
|
||||
.pos = pos2,
|
||||
.color = RGB(0.0,0.3*size/5,1),
|
||||
.move = move_linear(vel),
|
||||
.angle = ang+M_PI/4*side,
|
||||
.max_viewport_dist = 64,
|
||||
.flags = PFLAG_MANUALANGLE,
|
||||
);
|
||||
INVOKE_TASK_DELAYED(split_time, cirno_snowflake_proj_twist, ENT_BOX(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int burst = 0;; ++burst) {
|
||||
double angle_ofs = carg(global.plr.pos - boss->pos);
|
||||
int size = size_base + size_oscillation * sin(burst * 2.21);
|
||||
|
||||
for(int flake = 0; flake < flakes_per_burst; ++flake) {
|
||||
double angle = circle_angle(flake + flakes_per_burst / 2, flakes_per_burst) + angle_ofs;
|
||||
MoveParams move = move_asymptotic(launch_speed * cdir(angle), 0, 0.95);
|
||||
INVOKE_SUBTASK(make_snowflake, boss->pos, move, size, angle, &snowflake_projs);
|
||||
WAIT(flake_spawn_interval);
|
||||
}
|
||||
|
||||
WAIT(interval-3*size);
|
||||
WAIT(65 - 4 * (size_base + size_oscillation - size));
|
||||
|
||||
play_sound("redirect");
|
||||
// play_sound("shot_special1");
|
||||
|
||||
ENT_ARRAY_FOREACH(&snowflake_projs, Projectile *p, {
|
||||
spawn_projectile_highlight_effect(p)->shader_params.vector[0] = 0.75;
|
||||
color_lerp(&p->color, RGB(0.5, 0.5, 0.5), 0.5);
|
||||
p->move.velocity = 2 * cdir(p->angle);
|
||||
p->move.acceleration = -cdir(p->angle) * difficulty_value(0.1, 0.15, 0.2, 0.2);
|
||||
});
|
||||
|
||||
ENT_ARRAY_CLEAR(&snowflake_projs);
|
||||
WAIT(burst_interval);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue