taisei/src/stages/stage1/spells/crystal_blizzard.c
2024-05-17 14:11:48 +02:00

109 lines
2.8 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "spells.h"
TASK(crystal_wall) {
int num_crystals = difficulty_value(18, 21, 24, 27);
real spacing = VIEWPORT_W / (real)(num_crystals - 1);
real ofs = rng_real() - 1;
for(int i = 0; i < 30; ++i) {
play_sfx("shot1");
for(int c = 0; c < num_crystals; ++c) {
cmplx accel = 0.02*I + 0.01*I * ((c % 2) ? 1 : -1) * sin((c * 3 + global.frames) / 30.0);
PROJECTILE(
.proto = pp_crystal,
.pos = (ofs + c) * spacing + 20,
.color = (c % 2) ? RGB(0.2, 0.2, 0.4) : RGB(0.5, 0.5, 0.5),
.move = move_accelerated(0, accel),
.max_viewport_dist = 16,
);
}
WAIT(10);
}
}
TASK(cirno_frostbolt_trail, { BoxedProjectile proj; }) {
Projectile *p = TASK_BIND(ARGS.proj);
int period = 12;
WAIT(rng_irange(0, period + 1));
for(;;) {
stage1_spawn_stain(p->pos, rng_f32_angle(), 20);
WAIT(period);
}
}
TASK(cirno_frostbolt, { cmplx pos; cmplx vel; }) {
Projectile *p = TASK_BIND(PROJECTILE(
.proto = pp_wave,
.pos = ARGS.pos,
.color = RGBA(0.2, 0.2, 0.4, 0.0),
.move = move_asymptotic_simple(ARGS.vel, 5),
));
INVOKE_TASK(cirno_frostbolt_trail, ENT_BOX(p));
WAIT(difficulty_value(200, 300, 400, 500));
p->move.retention = 1.03;
}
DEFINE_EXTERN_TASK(stage1_spell_crystal_blizzard) {
Boss *boss = INIT_BOSS_ATTACK(&ARGS);
boss->move = move_from_towards(boss->pos, VIEWPORT_W / 2.0 + 300 * I, 0.1);
BEGIN_BOSS_ATTACK(&ARGS);
int frostbolt_period = difficulty_value(4, 3, 2, 1);
for(;;) {
INVOKE_SUBTASK_DELAYED(60, crystal_wall);
int charge_time = 120;
WAIT(330 - charge_time);
aniplayer_queue(&boss->ani, "(9)" ,0);
INVOKE_SUBTASK(common_charge, boss->pos, RGBA(0.5, 0.6, 2.0, 0.0), charge_time, .sound = COMMON_CHARGE_SOUNDS);
WAIT(charge_time);
boss->move = move_towards_exp(boss->move.velocity, global.plr.pos, 1, 0.1);
for(int t = 0; t < 370; ++t) {
play_sfx_loop("shot1_loop");
boss->move.attraction_point = global.plr.pos;
if(!(t % frostbolt_period)) {
cmplx aim = cnormalize(global.plr.pos - boss->pos) * cdir(rng_sreal() * 0.2);
cmplx vel = rng_range(0.01, 4) * aim;
INVOKE_TASK(cirno_frostbolt, boss->pos, vel);
}
if(!(t % 7)) {
play_sfx("shot1");
int cnt = global.diff - 1;
for(int i = 0; i < cnt; ++i) {
PROJECTILE(
.proto = pp_ball,
.pos = boss->pos,
.color = RGBA(0.1, 0.1, 0.5, 0.0),
.move = move_accelerated(0, 0.01 * cdir(global.frames/20.0 + i*M_TAU/cnt)),
);
}
}
WAIT(1);
}
boss->move.attraction_point = 0;
boss->move.attraction = 0;
boss->move.retention = 0.8;
aniplayer_queue(&boss->ani, "main" ,0);
}
}