remake Cirno's snowflake non

This commit is contained in:
Andrei Alexeyev 2019-10-06 13:50:58 +03:00
parent 75e99fa5c8
commit 20a417da97
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
7 changed files with 118 additions and 65 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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,
);

View file

@ -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);
}
}