Stage 5 Restructure (#247)

* initial commit (basic structure, does not compile)

* it compiles now

* moving some stuff around

* move spells/nonspells over to their own files, and retab the whole directory

* retab meson file (oops)

* newline shuffling

* clean up some imports, move functions to spellcards

* Update src/stages/stage5/background_anim.c

Co-authored-by: Andrei Alexeyev <akari@taisei-project.org>

* Apply suggestions from code review

Co-authored-by: Andrei Alexeyev <akari@taisei-project.org>

* code review changes

* change cloud_common to spawn_cloud

* move explosion survival to spells

* add missing timeline imports (oops)

* add missing comma

Co-authored-by: Andrei Alexeyev <akari@taisei-project.org>
This commit is contained in:
Alice D 2020-08-28 19:09:10 -04:00 committed by GitHub
parent 8f3b3fa0bc
commit 8f515e0f38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 2023 additions and 1744 deletions

View file

@ -16,7 +16,7 @@
#include "entity.h"
#include "util/glm.h"
#include "portrait.h"
#include "stages/stage5.h" // for unlockable bonus BGM
#include "stages/stage5/stage5.h" // for unlockable bonus BGM
static void ent_draw_boss(EntityInterface *ent);
static DamageResult ent_damage_boss(EntityInterface *ent, const DamageInfo *dmg);

View file

@ -12,10 +12,10 @@
#include "stages/stage1/stage1.h"
#include "stages/stage2/stage2.h"
#include "stages/stage5/stage5.h"
#include "stages/stage6/stage6.h"
#include "stages/stage3.h"
#include "stages/stage4.h"
#include "stages/stage5.h"
#include "stages/extra.h"
#ifdef DEBUG

View file

@ -4,6 +4,7 @@ stages_src = []
stages = [
'stage1',
'stage2',
'stage5',
'stage6'
]
@ -20,8 +21,6 @@ stages_src += files(
'stage3_events.c',
'stage4.c',
'stage4_events.c',
'stage5.c',
'stage5_events.c',
'extra.c',
)

View file

@ -1,243 +0,0 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "stage5.h"
#include "stage5_events.h"
#include "stage.h"
#include "stageutils.h"
#include "global.h"
#include "resource/model.h"
#include "portrait.h"
PRAGMA(message "Remove when this stage is modernized")
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
/*
* See the definition of AttackInfo in boss.h for information on how to set up the idmaps.
* To add, remove, or reorder spells, see this stage's header file.
*/
struct stage5_spells_s stage5_spells = {
.boss = {
.atmospheric_discharge = {
{ 0, 1, 2, 3}, AT_Spellcard, "High Voltage “Atmospheric Discharge”", 60, 44000,
iku_atmospheric, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.artificial_lightning = {
{ 4, 5, 6, 7}, AT_Spellcard, "Charge Sign “Artificial Lightning”", 75, 60000,
iku_lightning, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.induction_field = {
{12, 13, -1, -1}, AT_Spellcard, "Current Sign “Induction Field”", 60, 50000,
iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.inductive_resonance = {
{-1, -1, 14, 15}, AT_Spellcard, "Current Sign “Inductive Resonance”", 60, 50000,
iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.natural_cathode = {
{ 8, 9, 10, 11}, AT_Spellcard, "Spark Sign “Natural Cathode”", 60, 44000,
iku_cathode, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
},
.extra.overload = {
{ 0, 1, 2, 3}, AT_ExtraSpell, "Circuit Sign “Overload”", 60, 44000,
iku_extra, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
};
struct {
float light_strength;
float rotshift;
float omega;
float rad;
} stagedata;
static uint stage5_stairs_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 0, 0};
vec3 r = {0, 0, 6000};
return linear3dpos(s3d, pos, maxrange, p, r);
}
static void stage5_stairs_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_mat_mv_scale(300,300,300);
r_shader("tower_light");
r_uniform_sampler("tex", "stage5/tower");
r_uniform_vec3("lightvec", 0, 0, 0);
r_uniform_vec4("color", 0.1, 0.1, 0.5, 1);
r_uniform_float("strength", stagedata.light_strength);
r_draw_model("tower");
r_mat_mv_pop();
r_state_pop();
}
static void stage5_draw(void) {
r_mat_proj_perspective(STAGE3D_DEFAULT_FOVY, STAGE3D_DEFAULT_ASPECT, 100, 20000);
stage3d_draw(&stage_3d_context, 30000, 1, (Stage3DSegment[]) { stage5_stairs_draw, stage5_stairs_pos });
}
static void stage5_update(void) {
stage3d_update(&stage_3d_context);
TIMER(&global.timer);
float w = 0.005;
stagedata.rotshift += stagedata.omega;
stage_3d_context.crot[0] += stagedata.omega*0.5;
stagedata.rad += stagedata.omega*20;
int rot_time = 6350;
FROM_TO(rot_time, rot_time+50, 1)
stagedata.omega -= 0.005;
FROM_TO(rot_time+200, rot_time+250, 1)
stagedata.omega += 0.005;
stage_3d_context.cx[0] = stagedata.rad*cos(-w*global.frames);
stage_3d_context.cx[1] = stagedata.rad*sin(-w*global.frames);
stage_3d_context.cx[2] = -1700+w*3000/M_PI*global.frames;
stage_3d_context.crot[2] = stagedata.rotshift-180/M_PI*w*global.frames;
stagedata.light_strength *= 0.98;
if(frand() < 0.01)
stagedata.light_strength = 5+5*frand();
}
void iku_spell_bg(Boss *b, int t) {
fill_viewport(0, 300, 1, "stage5/spell_bg");
r_blend(BLEND_MOD);
fill_viewport(0, t*0.001, 0.7, "stage5/noise");
r_blend(BLEND_PREMUL_ALPHA);
r_mat_mv_push();
r_mat_mv_translate(0, -100, 0);
fill_viewport(t/100.0, 0, 0.5, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.75, 0, 0.6, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.5, 0, 0.7, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.25, 0, 0.8, "stage5/spell_clouds");
r_mat_mv_pop();
float opacity = 0.05 * stagedata.light_strength;
r_color4(opacity, opacity, opacity, opacity);
fill_viewport(0, 300, 1, "stage5/spell_lightning");
}
static void stage5_start(void) {
memset(&stagedata, 0, sizeof(stagedata));
stage3d_init(&stage_3d_context, 16);
stage_3d_context.crot[0] = 60;
stagedata.rotshift = 140;
stagedata.rad = 2800;
}
static void stage5_preload(void) {
portrait_preload_base_sprite("iku", NULL, RESF_DEFAULT);
portrait_preload_face_sprite("iku", "normal", RESF_DEFAULT);
preload_resources(RES_BGM, RESF_OPTIONAL, "stage5", "stage5boss", NULL);
preload_resources(RES_SPRITE, RESF_DEFAULT,
"part/blast_huge_halo",
"part/blast_huge_rays",
"stage5/noise",
"stage5/spell_bg",
"stage5/spell_clouds",
"stage5/spell_lightning",
"stage5/tower",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"tower_light",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/linear",
"lasers/accelerated",
"lasers/iku_cathode",
"lasers/iku_lightning",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,
"boss/iku",
"boss/iku_mid",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"tower",
NULL);
preload_resources(RES_SFX, RESF_OPTIONAL,
"boom",
"laser1",
"enemydeath",
NULL);
}
static void stage5_end(void) {
stage3d_shutdown(&stage_3d_context);
}
void stage5_skip(int t) {
skip_background_anim(stage5_update, t, &global.timer, &global.frames);
int mskip = global.timer;
if(mskip > 2900) {
mskip += 1100;
}
audio_bgm_seek_realtime(mskip / (double)FPS);
}
static void stage5_spellpractice_start(void) {
stage5_start();
skip_background_anim(stage5_update, 6960, &global.timer, NULL);
global.boss = stage5_spawn_iku(BOSS_DEFAULT_SPAWN_POS);
boss_add_attack_from_info(global.boss, global.stage->spell, true);
boss_start_attack(global.boss, global.boss->attacks);
stage_start_bgm("stage5boss");
}
static void stage5_spellpractice_events(void) {
}
ShaderRule stage5_shaders[] = { NULL };
StageProcs stage5_procs = {
.begin = stage5_start,
.preload = stage5_preload,
.end = stage5_end,
.draw = stage5_draw,
.update = stage5_update,
.event = stage5_events,
.shader_rules = stage5_shaders,
.spellpractice_procs = &stage5_spell_procs,
};
StageProcs stage5_spell_procs = {
.begin = stage5_spellpractice_start,
.preload = stage5_preload,
.end = stage5_end,
.draw = stage5_draw,
.update = stage5_update,
.event = stage5_spellpractice_events,
.shader_rules = stage5_shaders,
};

View file

@ -0,0 +1,50 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "background_anim.h"
#include "draw.h"
#include "global.h"
#include "stageutils.h"
void stage5_update(void) {
Stage5DrawData *stage5_draw_data = stage5_get_draw_data();
TIMER(&global.timer);
float w = 0.005;
stage5_draw_data->stairs.rotshift += stage5_draw_data->stairs.omega;
stage_3d_context.crot[0] += stage5_draw_data->stairs.omega*0.5;
stage5_draw_data->stairs.rad += stage5_draw_data->stairs.omega*20;
int rot_time = 6350;
FROM_TO(rot_time, rot_time+50, 1) {
stage5_draw_data->stairs.omega -= 0.005;
}
FROM_TO(rot_time+200, rot_time+250, 1) {
stage5_draw_data->stairs.omega += 0.005;
}
stage_3d_context.cx[0] = stage5_draw_data->stairs.rad*cos(-w*global.frames);
stage_3d_context.cx[1] = stage5_draw_data->stairs.rad*sin(-w*global.frames);
stage_3d_context.cx[2] = -1700+w*3000/M_PI*global.frames;
stage_3d_context.crot[2] = stage5_draw_data->stairs.rotshift-180/M_PI*w*global.frames;
stage5_draw_data->stairs.light_strength *= 0.98;
if (frand() < 0.01) {
stage5_draw_data->stairs.light_strength = 5+5*frand();
}
stage3d_update(&stage_3d_context);
}

View file

@ -0,0 +1,18 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_background_anim_h
#define IGUARD_stages_stage5_background_anim_h
#include "taisei.h"
#include "coroutine.h"
void stage5_update(void);
#endif // IGUARD_stages_stage5_background_anim_h

86
src/stages/stage5/draw.c Normal file
View file

@ -0,0 +1,86 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "draw.h"
#include "global.h"
#include "stageutils.h"
static Stage5DrawData *stage5_draw_data;
Stage5DrawData *stage5_get_draw_data(void) {
return NOT_NULL(stage5_draw_data);
}
void stage5_drawsys_init(void) {
stage5_draw_data = calloc(1, sizeof(*stage5_draw_data));
stage3d_init(&stage_3d_context, 16);
stage_3d_context.crot[0] = 60;
stage5_draw_data->stairs.rotshift = 140;
stage5_draw_data->stairs.rad = 2800;
}
void stage5_drawsys_shutdown(void) {
stage3d_shutdown(&stage_3d_context);
free(stage5_draw_data);
stage5_draw_data = NULL;
}
static uint stage5_stairs_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 0, 0};
vec3 r = {0, 0, 6000};
return linear3dpos(s3d, pos, maxrange, p, r);
}
static void stage5_stairs_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
r_mat_mv_translate(pos[0], pos[1], pos[2]);
r_mat_mv_scale(300,300,300);
r_shader("tower_light");
r_uniform_sampler("tex", "stage5/tower");
r_uniform_vec3("lightvec", 0, 0, 0);
r_uniform_vec4("color", 0.1, 0.1, 0.5, 1);
r_uniform_float("strength", stage5_draw_data->stairs.light_strength);
r_draw_model("tower");
r_mat_mv_pop();
r_state_pop();
}
void stage5_draw(void) {
r_mat_proj_perspective(STAGE3D_DEFAULT_FOVY, STAGE3D_DEFAULT_ASPECT, 100, 20000);
stage3d_draw(&stage_3d_context, 30000, 1, (Stage3DSegment[]) { stage5_stairs_draw, stage5_stairs_pos });
}
void iku_spell_bg(Boss *b, int t) {
fill_viewport(0, 300, 1, "stage5/spell_bg");
r_blend(BLEND_MOD);
fill_viewport(0, t*0.001, 0.7, "stage5/noise");
r_blend(BLEND_PREMUL_ALPHA);
r_mat_mv_push();
r_mat_mv_translate(0, -100, 0);
fill_viewport(t/100.0, 0, 0.5, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.75, 0, 0.6, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.5, 0, 0.7, "stage5/spell_clouds");
r_mat_mv_translate(0, 100, 0);
fill_viewport(t/100.0 * 0.25, 0, 0.8, "stage5/spell_clouds");
r_mat_mv_pop();
float opacity = 0.05 * stage5_draw_data->stairs.light_strength;
r_color4(opacity, opacity, opacity, opacity);
fill_viewport(0, 300, 1, "stage5/spell_lightning");
}

51
src/stages/stage5/draw.h Normal file
View file

@ -0,0 +1,51 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_draw_h
#define IGUARD_stages_stage5_draw_h
#include "taisei.h"
#include "stagedraw.h"
typedef struct Stage5DrawData {
struct {
float exponent;
float brightness;
} fog;
struct {
float r;
float g;
float b;
float mixfactor;
} color;
struct {
float light_strength;
float rotshift;
float omega;
float rad;
} stairs;
} Stage5DrawData;
void stage5_drawsys_init(void);
void stage5_drawsys_shutdown(void);
void stage5_draw(void);
void iku_spell_bg(Boss *b, int t);
Stage5DrawData *stage5_get_draw_data(void);
extern ShaderRule stage5_bg_effects[];
extern ShaderRule stage5_postprocess[];
#endif // IGUARD_stages_stage5_draw_h

116
src/stages/stage5/iku.c Normal file
View file

@ -0,0 +1,116 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "iku.h"
#include "stage5.h"
#include "common_tasks.h"
void iku_lightning_particle(cmplx pos, int t) {
if(!(t % 5)) {
char *part = frand() > 0.5 ? "lightning0" : "lightning1";
PARTICLE(
.sprite = part,
.pos = pos,
.color = RGBA(1.0, 1.0, 1.0, 0.0),
.timeout = 20,
.draw_rule = Fade,
.flags = PFLAG_REQUIREDPARTICLE,
.angle = frand()*2*M_PI,
);
}
}
void iku_slave_visual(Enemy *e, int t, bool render) {
if(render) {
return;
}
cmplx offset = (frand()-0.5)*10 + (frand()-0.5)*10.0*I;
if(e->args[2] && !(t % 5)) {
iku_lightning_particle(e->pos + 3*offset, t);
}
if(!(t % 3)) {
float alpha = 1;
if(!e->args[2]) {
alpha *= 0.03;
}
Color *clr = RGBA_MUL_ALPHA(0.1*alpha, 0.1*alpha, 0.6*alpha, 0.5*alpha);
clr->a = 0;
PARTICLE(
.sprite = "lightningball",
.pos = 0,
.color = clr,
.draw_rule = Fade,
.rule = enemy_flare,
.timeout = 50,
.args = { offset*0.1, add_ref(e) },
.flags = PFLAG_REQUIREDPARTICLE,
);
}
}
void iku_nonspell_spawn_cloud(void) {
tsrand_fill(4);
float v = (afrand(2)+afrand(3))*0.5+1.0;
PROJECTILE(
// FIXME: add prototype, or shove it into the basic ones somehow,
// or just replace this with some thing else
.sprite_ptr = get_sprite("part/lightningball"),
.size = 48 * (1+I),
.collision_size = 21.6 * (1+I),
.pos = VIEWPORT_W*afrand(0)-15.0*I,
.color = RGBA_MUL_ALPHA(0.2, 0.0, 0.4, 0.6),
.rule = accelerated,
.args = {
1-2*afrand(1)+v*I,
-0.01*I
},
.shader = "sprite_default",
);
}
static cmplx induction_bullet_traj(Projectile *p, float t) {
return p->pos0 + p->args[0]*t*cexp(p->args[1]*t);
}
int iku_induction_bullet(Projectile *p, int time) {
if(time < 0) {
return ACTION_ACK;
}
float t = time*sqrt(global.diff);
if(global.diff > D_Normal && !p->args[2]) {
t = time*0.6;
t = 230-t;
if(t < 0)
return ACTION_DESTROY;
}
p->pos = induction_bullet_traj(p,t);
if(time == 0) {
// don't lerp; the spawn position is very different on hard/lunatic and would cause false hits
p->prevpos = p->pos;
}
p->angle = carg(p->args[0]*cexp(p->args[1]*t)*(1+p->args[1]*t));
return 1;
}

23
src/stages/stage5/iku.h Normal file
View file

@ -0,0 +1,23 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_iku_h
#define IGUARD_stages_stage5_iku_h
#include "taisei.h"
#include "boss.h"
void iku_slave_visual(Enemy*, int, bool);
void iku_nonspell_spawn_cloud(void);
void iku_lightning_particle(cmplx, int);
int iku_induction_bullet(Projectile*, int);
#endif // IGUARD_stages_stage5_iku_h

View file

@ -0,0 +1,16 @@
stage5_src = files(
'background_anim.c',
'iku.c',
'draw.c',
'stage5.c',
'timeline.c',
'nonspells/boss_nonspell_1.c',
'nonspells/boss_nonspell_2.c',
'nonspells/boss_nonspell_3.c',
'spells/static_bomb.c',
'spells/atmospheric_discharge.c',
'spells/artificial_lightning.c',
'spells/induction.c',
'spells/natural_cathode.c',
'spells/overload.c'
)

View file

@ -0,0 +1,53 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "nonspells.h"
void iku_bolts(Boss *b, int time) {
int t = time % 400;
TIMER(&t);
FROM_TO(0, 400, 2) {
iku_nonspell_spawn_cloud();
}
FROM_TO(60, 400, 50) {
int i, c = 10+global.diff;
for(i = 0; i < c; i++) {
PROJECTILE(
.proto = pp_ball,
.pos = b->pos,
.color = RGBA(0.4, 1.0, 1.0, 0),
.rule = asymptotic,
.args = {
(i+2)*0.4*cexp(I*carg(global.plr.pos-b->pos))+0.2*(global.diff-1)*frand(),
3
},
);
}
play_sound("shot2");
play_sound("redirect");
}
FROM_TO(0, 70, 1)
GO_TO(b, 100+300.0*I, 0.02);
FROM_TO(100, 200, 1)
GO_TO(b, VIEWPORT_W/2+100.0*I, 0.02);
FROM_TO(230, 300, 1)
GO_TO(b, VIEWPORT_W-100+300.0*I, 0.02);
FROM_TO(330, 400, 1)
GO_TO(b, VIEWPORT_W/2+100.0*I, 0.02);
}

View file

@ -0,0 +1,63 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "nonspells.h"
static cmplx bolts2_laser(Laser *l, float t) {
if(t == EVENT_BIRTH) {
l->shader = r_shader_get_optional("lasers/iku_lightning");
return 0;
}
double diff = creal(l->args[2]);
return creal(l->args[0])+I*cimag(l->pos) + sign(cimag(l->args[0]-l->pos))*0.06*I*t*t + (20+4*diff)*sin(t*0.025*diff+creal(l->args[0]))*l->args[1];
}
void iku_bolts2(Boss *b, int time) {
int t = time % 400;
TIMER(&t);
// FIXME: ANOTHER one of these... get rid of this hack when attacks have proper state
static bool flip_laser;
if(time == EVENT_BIRTH) {
flip_laser = true;
}
FROM_TO(0, 400, 2) {
iku_nonspell_spawn_cloud();
}
FROM_TO(0, 400, 60) {
flip_laser = !flip_laser;
aniplayer_queue(&b->ani, flip_laser ? "dashdown_left" : "dashdown_right", 1);
aniplayer_queue(&b->ani, "main", 0);
create_lasercurve3c(creal(global.plr.pos), 100, 200, RGBA(0.3, 1, 1, 0), bolts2_laser, global.plr.pos, flip_laser*2-1, global.diff);
play_sfx_ex("laser1", 0, false);
}
FROM_TO_SND("shot1_loop", 0, 400, 5-global.diff)
if(frand() < 0.9) {
PROJECTILE(
.proto = pp_plainball,
.pos = b->pos,
.color = RGB(0.2,0,0.8),
.rule = linear,
.args = { cexp(0.1*I*_i) }
);
}
FROM_TO(0, 70, 1)
GO_TO(b, 100+200.0*I, 0.02);
FROM_TO(230, 300, 1)
GO_TO(b, VIEWPORT_W-100+200.0*I, 0.02);
}

View file

@ -0,0 +1,62 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "nonspells.h"
void iku_bolts3(Boss *b, int time) {
int t = time % 400;
TIMER(&t);
FROM_TO(0, 400, 2) {
iku_nonspell_spawn_cloud();
}
FROM_TO(60, 400, 60) {
aniplayer_queue(&b->ani, (_i&1) ? "dashdown_left" : "dashdown_right",1);
aniplayer_queue(&b->ani, "main", 0);
int i, c = 10+global.diff;
cmplx n = cexp(I*carg(global.plr.pos-b->pos)+0.1*I-0.2*I*frand());
for(i = 0; i < c; i++) {
PROJECTILE(
.proto = pp_ball,
.pos = b->pos,
.color = RGBA(0.4, 1.0, 1.0, 0.0),
.rule = asymptotic,
.args = {
(i+2)*0.4*n+0.2*(global.diff-1)*frand(),
3
},
);
}
play_sound("shot2");
play_sound("redirect");
}
FROM_TO_SND("shot1_loop", 0, 400, 5-global.diff)
if(frand() < 0.9) {
PROJECTILE(
.proto = pp_plainball,
.pos = b->pos,
.color = RGB(0.2,0,0.8),
.rule = linear,
.args = { cexp(0.1*I*_i) }
);
}
FROM_TO(0, 70, 1) {
GO_TO(b, 100+200.0*I, 0.02);
}
FROM_TO(230, 300, 1) {
GO_TO(b, VIEWPORT_W-100+200.0*I, 0.02);
}
}

View file

@ -0,0 +1,22 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_nonspells_nonspells_h
#define IGUARD_stages_stage5_nonspells_nonspells_h
#include "taisei.h"
#include "common_tasks.h"
#include "stages/stage5/iku.h"
void iku_bolts(Boss*, int);
void iku_bolts2(Boss*, int);
void iku_bolts3(Boss*, int);
#endif // IGUARD_stages_stage5_nonspells_nonspells_h

View file

@ -0,0 +1,155 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
static int zigzag_bullet(Projectile *p, int t) {
if(t < 0) {
return ACTION_ACK;
}
int l = 50;
p->pos = p->pos0+(abs(((2*t)%l)-l/2)*I+t)*2*p->args[0];
if(t%2 == 0) {
PARTICLE(
.sprite = "lightningball",
.pos = p->pos,
.color = RGBA(0.1, 0.1, 0.6, 0.0),
.timeout = 15,
.draw_rule = Fade,
);
}
return ACTION_NONE;
}
static int lightning_slave(Enemy *e, int t) {
if(t < 0)
return 1;
if(t > 200)
return ACTION_DESTROY;
TIMER(&t);
e->pos += e->args[0];
FROM_TO(0,200,20)
e->args[0] *= cexp(I * (0.25 + 0.25 * frand() * M_PI));
FROM_TO(0, 200, 3)
if(cabs(e->pos-global.plr.pos) > 60) {
Color *clr = RGBA(1-1/(1+0.01*_i), 0.5-0.01*_i, 1, 0);
Projectile *p = PROJECTILE(
.proto = pp_wave,
.pos = e->pos,
.color = clr,
.rule = asymptotic,
.args = {
0.75*e->args[0]/cabs(e->args[0])*I,
10
},
);
if(projectile_in_viewport(p)) {
for(int i = 0; i < 3; ++i) {
tsrand_fill(2);
iku_lightning_particle(p->pos + 5 * afrand(0) * cexp(I*M_PI*2*afrand(1)), 0);
}
play_sfx_ex("shot3", 0, false);
}
}
return 1;
}
void iku_lightning(Boss *b, int time) {
int t = time % 141;
if(time == EVENT_DEATH) {
enemy_kill_all(&global.enemies);
return;
}
if(time < 0) {
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.03);
return;
}
TIMER(&t);
GO_TO(b,VIEWPORT_W/2+tanh(sin(time/100))*200+I*VIEWPORT_H/3+I*(cos(t/200)-1)*50,0.03);
AT(0) {
play_sound("charge_generic");
}
FROM_TO(0, 60, 1) {
cmplx n = cexp(2.0*I*M_PI*frand());
float l = 150*frand()+50;
float s = 4+_i*0.01;
float alpha = 0.5;
PARTICLE(
.sprite = "lightningball",
.pos = b->pos+l*n,
.color = RGBA(0.1*alpha, 0.1*alpha, 0.6*alpha, 0),
.draw_rule = Fade,
.rule = linear,
.timeout = l/s,
.args = { -s*n },
);
}
if(global.diff >= D_Hard && time > 0 && !(time%100)) {
int c = 7 + 2 * (global.diff == D_Lunatic);
for(int i = 0; i<c; i++) {
PROJECTILE(
.proto = pp_bigball,
.pos = b->pos,
.color = RGBA(0.5, 0.1, 1.0, 0.0),
.rule = zigzag_bullet,
.args = { cexp(2*M_PI*I/c*i+I*carg(global.plr.pos-b->pos)) },
);
}
play_sound("redirect");
play_sound("shot_special1");
}
AT(100) {
aniplayer_hard_switch(&b->ani, ((time/141)&1) ? "dashdown_left" : "dashdown_right",1);
aniplayer_queue(&b->ani, "main", 0);
int c = 40;
int l = 200;
int s = 10;
for(int i=0; i < c; i++) {
cmplx n = cexp(2.0*I*M_PI*frand());
PARTICLE(
.sprite = "smoke",
.pos = b->pos,
.color = RGBA(0.4, 0.4, 1.0, 0.0),
.draw_rule = Fade,
.rule = linear,
.timeout = l/s,
.args = { s*n },
);
}
for(int i = 0; i < global.diff+1; i++){
create_enemy1c(b->pos, ENEMY_IMMUNE, NULL, lightning_slave, 10*cexp(I*carg(global.plr.pos - b->pos)+2.0*I*M_PI/(global.diff+1)*i));
}
play_sound("shot_special1");
}
}

View file

@ -0,0 +1,68 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
void iku_atmospheric(Boss *b, int time) {
if(time < 0) {
GO_TO(b, VIEWPORT_W/2+200.0*I, 0.06);
return;
}
int t = time % 500;
TIMER(&t);
GO_TO(b,VIEWPORT_W/2+tanh(sin(time/100))*(200-100*(global.diff==D_Easy))+I*VIEWPORT_H/3+I*(cos(t/200)-1)*50,0.03);
FROM_TO(0, 500, 23-2*global.diff) {
tsrand_fill(4);
cmplx p1 = VIEWPORT_W*afrand(0) + VIEWPORT_H/2*I*afrand(1);
cmplx p2 = p1 + (120+20*global.diff)*cexp(0.5*I-afrand(2)*I)*(1-2*(afrand(3) > 0.5));
int i;
int c = 6+global.diff;
for(i = -c*0.5; i <= c*0.5; i++) {
PROJECTILE(
.proto = pp_ball,
.pos = p1+(p2-p1)/c*i,
.color = RGBA(1-1/(1+fabs(0.1*i)), 0.5-0.1*abs(i), 1, 0),
.rule = accelerated,
.args = {
0, (0.004+0.001*global.diff)*cexp(I*carg(p2-p1)+I*M_PI/2+0.2*I*i)
},
);
}
play_sound("shot_special1");
play_sound("redirect");
}
FROM_TO(0, 500, 7-global.diff) {
if(global.diff >= D_Hard) {
PROJECTILE(
.proto = pp_thickrice,
.pos = VIEWPORT_W*frand(),
.color = RGB(0,0.3,0.7),
.rule = accelerated,
.args = { 0, 0.01*I }
);
}
else {
PROJECTILE(
.proto = pp_rice,
.pos = VIEWPORT_W*frand(),
.color = RGB(0,0.3,0.7),
.rule = linear,
.args = { 2*I }
);
}
}
}

View file

@ -0,0 +1,56 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
void iku_induction(Boss *b, int t) {
// thwarf safespots
cmplx ofs = global.diff > D_Normal ? 10*I : 0;
GO_TO(b, VIEWPORT_W/2+200.0*I + ofs, 0.03);
if(t < 0) {
return;
}
TIMER(&t);
AT(0) {
aniplayer_queue(&b->ani, "dashdown_wait", 0);
}
FROM_TO_SND("shot1_loop", 0, 18000, 8) {
play_sound("redirect");
int i,j;
int c = 6;
int c2 = 6-(global.diff/4);
for(i = 0; i < c; i++) {
for(j = 0; j < 2; j++) {
Color *clr = RGBA(1-1/(1+0.1*(_i%c2)), 0.5-0.1*(_i%c2), 1.0, 0.0);
float shift = 0.6*(_i/c2);
float a = -0.0002*(global.diff-D_Easy);
if(global.diff == D_Hard)
a += 0.0005;
PROJECTILE(
.proto = pp_ball,
.pos = b->pos,
.color = clr,
.rule = iku_induction_bullet,
.args = {
2*cexp(2.0*I*M_PI/c*i+I*M_PI/2+I*shift),
(0.01+0.001*global.diff)*I*(1-2*j)+a
},
.max_viewport_dist = 400*(global.diff>=D_Hard),
);
}
}
}
}

View file

@ -0,0 +1,59 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
static cmplx cathode_laser(Laser *l, float t) {
if(t == EVENT_BIRTH) {
l->shader = r_shader_get_optional("lasers/iku_cathode");
return 0;
}
l->args[1] = I*cimag(l->args[1]);
return l->pos + l->args[0]*t*cexp(l->args[1]*t);
}
void iku_cathode(Boss *b, int t) {
GO_TO(b, VIEWPORT_W/2+200.0*I, 0.02);
TIMER(&t)
FROM_TO(50, 18000, 70-global.diff*10) {
aniplayer_hard_switch(&b->ani, (_i&1) ? "dashdown_left" : "dashdown_right",1);
aniplayer_queue(&b->ani,"main",0);
int i;
int c = 7+global.diff/2;
double speedmod = 1-0.3*(global.diff == D_Lunatic);
for(i = 0; i < c; i++) {
PROJECTILE(
.proto = pp_bigball,
.pos = b->pos,
.color = RGBA(0.2, 0.4, 1.0, 0.0),
.rule = iku_induction_bullet,
.args = {
speedmod*2*cexp(2.0*I*M_PI*frand()),
speedmod*0.01*I*(1-2*(_i&1)),
1
},
);
if(i < c*3/4)
create_lasercurve2c(b->pos, 60, 200, RGBA(0.4, 1, 1, 0), cathode_laser, 2*cexp(2.0*I*M_PI*M_PI*frand()), 0.015*I*(1-2*(_i&1)));
}
// XXX: better ideas?
play_sound("shot_special1");
play_sound("redirect");
play_sound("shot3");
play_sound("shot2");
}
}

View file

@ -0,0 +1,279 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
static Enemy* iku_overload_find_next_slave(cmplx from, double playerbias) {
Enemy *nearest = NULL, *e;
double dist, mindist = INFINITY;
cmplx org = from + playerbias * cexp(I*(carg(global.plr.pos - from)));
for(e = global.enemies.first; e; e = e->next) {
if(e->args[2]) {
continue;
}
dist = cabs(e->pos - org);
if(dist < mindist) {
nearest = e;
mindist = dist;
}
}
return nearest;
}
static int iku_overload_trigger_bullet(Projectile *p, int t) {
if(t == EVENT_DEATH) {
free_ref(p->args[1]);
return ACTION_ACK;
}
if(t < 0) {
return ACTION_ACK;
}
Enemy *target = REF(p->args[1]);
if(!target) {
return ACTION_DESTROY;
}
if(creal(p->args[2]) < 0) {
linear(p, t);
if(cabs(p->pos - target->pos) < 5) {
p->pos = target->pos;
target->args[1] = 1;
p->args[2] = 55 - 5 * global.diff;
target->args[3] = global.frames + p->args[2];
play_sound("shot_special1");
}
} else {
p->args[2] = approach(creal(p->args[2]), 0, 1);
play_sfx_loop("charge_generic");
}
if(creal(p->args[2]) == 0) {
int cnt = 6 + 2 * global.diff;
for(int i = 0; i < cnt; ++i) {
cmplx dir = cexp(I*(t + i*2*M_PI/cnt));
PROJECTILE(
.proto = pp_bigball,
.pos = p->pos,
.color = RGBA(1.0, 0.5, 0.0, 0.0),
.rule = asymptotic,
.args = { 1.1*dir, 5 },
);
PROJECTILE(
.proto = pp_bigball,
.pos = p->pos,
.color = RGBA(0.0, 0.5, 1.0, 0.0),
.rule = asymptotic,
.args = { dir, 10 },
);
}
stage_shake_view(40);
aniplayer_hard_switch(&global.boss->ani,"main_mirror",0);
play_sound("boom");
return ACTION_DESTROY;
}
p->angle = global.frames + t;
tsrand_fill(5);
PARTICLE(
.sprite = afrand(0) > 0.5 ? "lightning0" : "lightning1",
.pos = p->pos + 3 * (anfrand(1)+I*anfrand(2)),
.angle = afrand(3) * 2 * M_PI,
.color = RGBA(1.0, 0.7 + 0.2 * anfrand(4), 0.4, 0.0),
.timeout = 20,
.draw_rule = GrowFade,
.args = { 0, 2.4 },
);
return ACTION_NONE;
}
static void iku_overload_fire_trigger_bullet(void) {
Enemy *e = iku_overload_find_next_slave(global.boss->pos, 250);
aniplayer_hard_switch(&global.boss->ani,"dashdown_left",1);
aniplayer_queue(&global.boss->ani,"main",0);
if(!e) {
return;
}
Boss *b = global.boss;
PROJECTILE(
.proto = pp_soul,
.pos = b->pos,
.color = RGBA(0.2, 0.2, 1.0, 0.0),
.rule = iku_overload_trigger_bullet,
.args = {
3*cexp(I*carg(e->pos - b->pos)),
add_ref(e),
-1
},
.flags = PFLAG_NOCLEAR,
);
play_sound("shot_special1");
play_sound("enemydeath");
play_sound("shot2");
}
static void iku_overload_slave_visual(Enemy *e, int t, bool render) {
iku_slave_visual(e, t, render);
if(render) {
return;
}
if(e->args[2] && !(t % 5)) {
cmplx offset = (frand()-0.5)*30 + (frand()-0.5)*20.0*I;
PARTICLE(
.sprite = "smoothdot",
.pos = offset,
.color = e->args[1] ? RGBA(1.0, 0.5, 0.0, 0.0) : RGBA(0.0, 0.5, 0.5, 0.0),
.draw_rule = Shrink,
.rule = enemy_flare,
.timeout = 50,
.args = {
(-50.0*I-offset)/50.0,
add_ref(e)
},
);
}
}
static int iku_overload_slave(Enemy *e, int t) {
GO_TO(e, e->args[0], 0.05);
if(e->args[1]) {
if(creal(e->args[1]) < 2) {
e->args[1] += 1;
return 0;
}
if(global.frames == creal(e->args[3])) {
cmplx o2 = e->args[2];
e->args[2] = 0;
Enemy *new = iku_overload_find_next_slave(e->pos, 75);
e->args[2] = o2;
if(new && e != new) {
e->args[1] = 0;
e->args[2] = new->args[2] = 600;
new->args[1] = 1;
new->args[3] = global.frames + 55 - 5 * global.diff;
Laser *l = create_laserline_ab(e->pos, new->pos, 10, 30, e->args[2], RGBA(0.3, 1, 1, 0));
l->ent.draw_layer = LAYER_LASER_LOW;
l->unclearable = true;
if(global.diff > D_Easy) {
int cnt = floor(global.diff * 2.5), i;
double r = frand() * 2 * M_PI;
for(i = 0; i < cnt; ++i) {
PROJECTILE(
.proto = pp_rice,
.pos = e->pos,
.color = RGBA(1, 1, 0, 0),
.rule = asymptotic,
.args = { 2*cexp(I*(r+i*2*M_PI/cnt)), 2 },
);
}
play_sound("shot2");
}
play_sound("redirect");
} else {
Enemy *o;
Laser *l;
int cnt = 6 + 2 * global.diff, i;
e->args[2] = 1;
for(o = global.enemies.first; o; o = o->next) {
if(!o->args[2])
continue;
for(i = 0; i < cnt; ++i) {
PROJECTILE(
.proto = pp_ball,
.pos = o->pos,
.color = RGBA(0, 1, 1, 0),
.rule = asymptotic,
.args = { 1.5*cexp(I*(t + i*2*M_PI/cnt)), 8},
);
}
o->args[1] = 0;
o->args[2] = 0;
stage_shake_view(5);
}
for(l = global.lasers.first; l; l = l->next) {
l->deathtime = global.frames - l->birthtime + 20;
}
play_sound("boom");
iku_overload_fire_trigger_bullet();
}
}
}
if(e->args[2]) {
e->args[2] -= 1;
}
return 0;
}
void iku_overload(Boss *b, int t) {
TIMER(&t);
AT(EVENT_DEATH) {
enemy_kill_all(&global.enemies);
}
if(t < 0) {
return;
}
GO_TO(b, VIEWPORT_W/2+50.0*I, 0.02);
AT(0) {
int i, j;
int cnt = 5;
double step = VIEWPORT_W / (double)cnt;
for(i = 0; i < cnt; ++i) {
for(j = 0; j < cnt; ++j) {
cmplx epos = step * (0.5 + i) + (step * j + 125) * I;
create_enemy4c(b->pos, ENEMY_IMMUNE, iku_overload_slave_visual, iku_overload_slave, epos, 0, 0, 1);
}
}
}
AT(60) {
iku_overload_fire_trigger_bullet();
}
}

View file

@ -0,0 +1,25 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_spells_spells_h
#define IGUARD_stages_stage5_spells_spells_h
#include "taisei.h"
#include "common_tasks.h"
#include "stages/stage5/iku.h"
void iku_atmospheric(Boss *, int);
void iku_lightning(Boss *, int);
void iku_induction(Boss *, int);
void iku_cathode(Boss *, int);
void iku_overload(Boss *, int);
void iku_mid_intro(Boss *, int t);
#endif // IGUARD_stages_stage5_spells_spells_h

View file

@ -0,0 +1,98 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "spells.h"
static int iku_explosion(Enemy *e, int t) {
TIMER(&t)
AT(EVENT_KILLED) {
spawn_items(e->pos,
ITEM_POINTS, 5,
ITEM_POWER, 5,
ITEM_LIFE, creal(e->args[1])
);
PARTICLE(
.sprite = "blast_huge_rays",
.color = color_add(RGBA(0, 0.2 + 0.5 * frand(), 0.5 + 0.5 * frand(), 0.0), RGBA(1, 1, 1, 0)),
.pos = e->pos,
.timeout = 60 + 10 * frand(),
.draw_rule = ScaleFade,
.args = { 0, 0, (0 + 3*I) * (1 + 0.2 * frand()) },
.angle = frand() * 2 * M_PI,
.layer = LAYER_PARTICLE_HIGH | 0x42,
.flags = PFLAG_REQUIREDPARTICLE,
);
PARTICLE(
.sprite = "blast_huge_halo",
.pos = e->pos,
.color = RGBA(0.3 * frand(), 0.3 * frand(), 1.0, 0),
.timeout = 200 + 24 * frand(),
.draw_rule = ScaleFade,
.args = { 0, 0, (0.25 + 2.5*I) * (1 + 0.2 * frand()) },
.layer = LAYER_PARTICLE_HIGH | 0x41,
.angle = frand() * 2 * M_PI,
.flags = PFLAG_REQUIREDPARTICLE,
);
play_sound("boom");
return 1;
}
FROM_TO(0, 80, 1) {
GO_TO(e, e->pos0 + e->args[0] * 80, 0.05);
}
FROM_TO(90, 300, 7-global.diff) {
PROJECTILE(
.proto = pp_soul,
.pos = e->pos,
.color = RGBA(0, 0, 1, 0),
.rule = asymptotic,
.args = { 4*cexp(0.5*I*_i), 3 }
);
play_sound("shot_special1");
}
FROM_TO(200, 720, 6-global.diff) {
for(int i = 1; i >= -1; i -= 2) {
PROJECTILE(
.proto = pp_rice,
.pos = e->pos,
.color = RGB(1,0,0),
.rule = asymptotic,
.args = { i*2*cexp(-0.3*I*_i+frand()*I), 3 }
);
}
play_sound("shot3");
}
FROM_TO(500-30*(global.diff-D_Easy), 800, 100-10*global.diff) {
create_laserline(e->pos, 10*cexp(I*carg(global.plr.pos-e->pos)+0.04*I*(1-2*frand())), 60, 120, RGBA(1, 0.3, 1, 0));
play_sfx_delayed("laser1", 0, true, 45);
}
return 1;
}
void iku_mid_intro(Boss *b, int t) {
TIMER(&t);
b->pos += -1-7.0*I+10*t*(cimag(b->pos)<-200);
FROM_TO(90, 110, 10) {
create_enemy3c(b->pos, ENEMY_IMMUNE, iku_slave_visual, iku_explosion, -2-0.5*_i+I*_i, _i == 1,1);
}
AT(960)
enemy_kill_all(&global.enemies);
}

126
src/stages/stage5/stage5.c Normal file
View file

@ -0,0 +1,126 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "stage5.h"
#include "draw.h"
#include "background_anim.h"
#include "iku.h"
#include "spells/spells.h"
#include "timeline.h"
#include "global.h"
#include "portrait.h"
#include "common_tasks.h"
struct stage5_spells_s stage5_spells = {
.boss = {
.atmospheric_discharge = {
{ 0, 1, 2, 3}, AT_Spellcard, "High Voltage “Atmospheric Discharge”", 60, 44000,
iku_atmospheric, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.artificial_lightning = {
{ 4, 5, 6, 7}, AT_Spellcard, "Charge Sign “Artificial Lightning”", 75, 60000,
iku_lightning, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.induction_field = {
{12, 13, -1, -1}, AT_Spellcard, "Current Sign “Induction Field”", 60, 50000,
iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.inductive_resonance = {
{-1, -1, 14, 15}, AT_Spellcard, "Current Sign “Inductive Resonance”", 60, 50000,
iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
.natural_cathode = {
{ 8, 9, 10, 11}, AT_Spellcard, "Spark Sign “Natural Cathode”", 60, 44000,
iku_cathode, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
},
.extra.overload = {
{ 0, 1, 2, 3}, AT_ExtraSpell, "Circuit Sign “Overload”", 60, 44000,
iku_overload, iku_spell_bg, BOSS_DEFAULT_GO_POS, 5
},
};
static void stage5_start(void) {
stage5_drawsys_init();
}
static void stage5_preload(void) {
portrait_preload_base_sprite("iku", NULL, RESF_DEFAULT);
portrait_preload_face_sprite("iku", "normal", RESF_DEFAULT);
preload_resources(RES_BGM, RESF_OPTIONAL, "stage5", "stage5boss", NULL);
preload_resources(RES_SPRITE, RESF_DEFAULT,
"part/blast_huge_halo",
"part/blast_huge_rays",
"stage5/noise",
"stage5/spell_bg",
"stage5/spell_clouds",
"stage5/spell_lightning",
"stage5/tower",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
"tower_light",
NULL);
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
"lasers/linear",
"lasers/accelerated",
"lasers/iku_cathode",
"lasers/iku_lightning",
NULL);
preload_resources(RES_ANIM, RESF_DEFAULT,
"boss/iku",
"boss/iku_mid",
NULL);
preload_resources(RES_MODEL, RESF_DEFAULT,
"tower",
NULL);
preload_resources(RES_SFX, RESF_OPTIONAL,
"boom",
"laser1",
"enemydeath",
NULL);
}
static void stage5_end(void) {
stage5_drawsys_shutdown();
}
static void stage5_spellpractice_start(void) {
stage5_start();
global.boss = stage5_spawn_iku(BOSS_DEFAULT_SPAWN_POS);
boss_add_attack_from_info(global.boss, global.stage->spell, true);
boss_start_attack(global.boss, global.boss->attacks);
stage_start_bgm("stage5boss");
}
ShaderRule stage5_shaders[] = { NULL };
StageProcs stage5_procs = {
.begin = stage5_start,
.preload = stage5_preload,
.end = stage5_end,
.draw = stage5_draw,
.update = stage5_update,
.event = stage5_events,
.shader_rules = stage5_shaders,
.spellpractice_procs = &stage5_spell_procs,
};
StageProcs stage5_spell_procs = {
.begin = stage5_spellpractice_start,
.preload = stage5_preload,
.end = stage5_end,
.draw = stage5_draw,
.update = stage5_update,
.shader_rules = stage5_shaders,
};

View file

@ -6,8 +6,8 @@
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_h
#define IGUARD_stages_stage5_h
#ifndef IGUARD_stages_stage5_stage5_h
#define IGUARD_stages_stage5_stage5_h
#include "taisei.h"
@ -36,6 +36,6 @@ extern struct stage5_spells_s {
extern StageProcs stage5_procs;
extern StageProcs stage5_spell_procs;
void stage5_skip(int t);
void stage5_skip(int);
#endif // IGUARD_stages_stage5_h
#endif // IGUARD_stages_stage5_stage5_h

View file

@ -0,0 +1,571 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "timeline.h"
#include "stage5.h"
#include "nonspells/nonspells.h"
#include "spells/spells.h"
TASK(boss_appear_stub, NO_ARGS) {
log_warn("FIXME");
}
static void stage5_dialog_pre_boss(void) {
PlayerMode *pm = global.plr.mode;
Stage5PreBossDialogEvents *e;
INVOKE_TASK_INDIRECT(Stage5PreBossDialog, pm->dialog->Stage5PreBoss, &e);
INVOKE_TASK_WHEN(&e->boss_appears, boss_appear_stub);
INVOKE_TASK_WHEN(&e->music_changes, common_start_bgm, "stage5boss");
}
static void stage5_dialog_post_boss(void) {
PlayerMode *pm = global.plr.mode;
INVOKE_TASK_INDIRECT(Stage5PostBossDialog, pm->dialog->Stage5PostBoss);
}
static void stage5_dialog_post_midboss(void) {
PlayerMode *pm = global.plr.mode;
INVOKE_TASK_INDIRECT(Stage5PostMidBossDialog, pm->dialog->Stage5PostMidBoss);
}
static int stage5_greeter(Enemy *e, int t) {
TIMER(&t)
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 2, ITEM_POWER, 2);
return 1;
}
e->moving = true;
e->dir = creal(e->args[0]) < 0;
FROM_TO(0, 50, 1) {
GO_TO(e, e->pos0 + e->args[0] * 50, 0.05);
}
if(t > 200)
e->pos += e->args[0];
FROM_TO(80, 180, 20) {
for(int i = -(int)global.diff; i <= (int)global.diff; i++) {
PROJECTILE(
.proto = pp_bullet,
.pos = e->pos,
.color = RGB(0.0, 0.0, 1.0),
.rule = asymptotic,
.args = {
(3.5+(global.diff == D_Lunatic))*cexp(I*carg(global.plr.pos-e->pos) + 0.06*I*i),
5
}
);
}
play_sound("shot1");
}
return 1;
}
static int stage5_lightburst(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 4, ITEM_POWER, 2);
return 1;
}
FROM_TO(0, 70, 1) {
GO_TO(e, e->pos0 + e->args[0] * 70, 0.05);
}
if(t > 200)
e->pos += e->args[0];
FROM_TO_SND("shot1_loop", 20, 300, 5) {
int c = 5+global.diff;
for(int i = 0; i < c; i++) {
cmplx n = cexp(I*carg(global.plr.pos) + 2.0*I*M_PI/c*i);
PROJECTILE(
.proto = pp_ball,
.pos = e->pos + 50*n*cexp(-0.4*I*_i*global.diff),
.color = RGB(0.3, 0, 0.7),
.rule = asymptotic,
.args = { 3*n, 3 }
);
}
play_sound("shot2");
}
return 1;
}
static int stage5_swirl(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 1);
return 1;
}
if(t > creal(e->args[1]) && t < cimag(e->args[1]))
e->args[0] *= e->args[2];
e->pos += e->args[0];
FROM_TO(0, 400, 26-global.diff*4) {
for(int i = 1; i >= -1; i -= 2) {
PROJECTILE(
.proto = pp_bullet,
.pos = e->pos,
.color = RGB(0.3, 0.4, 0.5),
.rule = asymptotic,
.args = { i*2*e->args[0]*I/cabs(e->args[0]), 3 }
);
}
play_sound("shot1");
}
return 1;
}
static int stage5_limiter(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 4, ITEM_POWER, 4);
return 1;
}
e->pos += e->args[0];
FROM_TO_SND("shot1_loop", 0, 1200, 3) {
uint f = PFLAG_NOSPAWNFADE;
double base_angle = carg(global.plr.pos - e->pos);
for(int i = 1; i >= -1; i -= 2) {
double a = i * 0.2 - 0.1 * (global.diff / 4) + i * 3.0 / (_i + 1);
cmplx aim = cexp(I * (base_angle + a));
PROJECTILE(
.proto = pp_rice,
.pos = e->pos,
.color = RGB(0.5,0.1,0.2),
.rule = asymptotic,
.args = { 10*aim, 2 },
.flags = f,
);
}
}
return 1;
}
static int stage5_laserfairy(Enemy *e, int t) {
TIMER(&t)
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 5, ITEM_POWER, 5);
return 1;
}
FROM_TO(0, 100, 1) {
GO_TO(e, e->pos0 + e->args[0] * 100, 0.05);
}
if(t > 700)
e->pos -= e->args[0];
FROM_TO(100, 700, (7-global.diff)*(1+(int)creal(e->args[1]))) {
cmplx n = cexp(I*carg(global.plr.pos-e->pos)+(0.2-0.02*global.diff)*I*_i);
float fac = (0.5+0.2*global.diff);
create_lasercurve2c(e->pos, 100, 300, RGBA(0.7, 0.3, 1, 0), las_accel, fac*4*n, fac*0.05*n);
PROJECTILE(
.proto = pp_plainball,
.pos = e->pos,
.color = RGBA(0.7, 0.3, 1, 0),
.rule = accelerated,
.args = { fac*4*n, fac*0.05*n }
);
play_sfx_ex("shot_special1", 0, true);
}
return 1;
}
static int stage5_miner(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 2);
return 1;
}
e->pos += e->args[0];
FROM_TO(0, 600, 5-global.diff/2) {
tsrand_fill(2);
PROJECTILE(
.proto = pp_rice,
.pos = e->pos + 20*cexp(2.0*I*M_PI*afrand(0)),
.color = RGB(0,0,cabs(e->args[0])),
.rule = linear,
.args = { cexp(2.0*I*M_PI*afrand(1)) }
);
play_sfx_ex("shot3", 0, false);
}
return 1;
}
static void iku_intro(Boss *b, int t) {
GO_TO(b, VIEWPORT_W/2+240.0*I, 0.015);
if(t == 160)
stage5_dialog_pre_boss();
}
Boss* stage5_spawn_iku(cmplx pos) {
Boss *b = create_boss("Nagae Iku", "iku", pos);
boss_set_portrait(b, "iku", NULL, "normal");
b->glowcolor = *RGBA_MUL_ALPHA(0.2, 0.4, 0.5, 0.5);
b->shadowcolor = *RGBA_MUL_ALPHA(0.65, 0.2, 0.75, 0.5);
return b;
}
static void midboss_dummy(Boss *b, int t) { }
static Boss *stage5_spawn_midboss(void) {
Boss *b = create_boss("Bombs?", "iku_mid", VIEWPORT_W+800.0*I);
b->glowcolor = *RGB(0.2, 0.4, 0.5);
b->shadowcolor = *RGBA_MUL_ALPHA(0.65, 0.2, 0.75, 0.5);
Attack *a = boss_add_attack(b, AT_SurvivalSpell, "Discharge Bombs", 16, 10, iku_mid_intro, NULL);
boss_set_attack_bonus(a, 5);
// suppress the boss death effects (this triggers the "boss fleeing" case)
boss_add_attack(b, AT_Move, "", 0, 0, midboss_dummy, NULL);
boss_start_attack(b, b->attacks);
b->attacks->starttime = global.frames; // HACK: thwart attack delay
return b;
}
static Boss* stage5_spawn_boss(void) {
Boss *b = stage5_spawn_iku(VIEWPORT_W/2-200.0*I);
boss_add_attack(b, AT_Move, "Introduction", 4, 0, iku_intro, NULL);
boss_add_attack(b, AT_Normal, "Bolts1", 40, 24000, iku_bolts, NULL);
boss_add_attack_from_info(b, &stage5_spells.boss.atmospheric_discharge, false);
boss_add_attack(b, AT_Normal, "Bolts2", 45, 27000, iku_bolts2, NULL);
boss_add_attack_from_info(b, &stage5_spells.boss.artificial_lightning, false);
boss_add_attack(b, AT_Normal, "Bolts3", 50, 30000, iku_bolts3, NULL);
if(global.diff < D_Hard) {
boss_add_attack_from_info(b, &stage5_spells.boss.induction_field, false);
} else {
boss_add_attack_from_info(b, &stage5_spells.boss.inductive_resonance, false);
}
boss_add_attack_from_info(b, &stage5_spells.boss.natural_cathode, false);
boss_add_attack_from_info(b, &stage5_spells.extra.overload, false);
boss_start_attack(b, b->attacks);
return b;
}
static int stage5_magnetto(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 5, ITEM_POWER, 5);
return 1;
}
if(t < 0) {
return 1;
}
cmplx offset = (frand()-0.5)*10 + (frand()-0.5)*10.0*I;
iku_lightning_particle(e->pos + 3*offset, t);
FROM_TO(0, 70, 1) {
GO_TO(e, e->args[0], 0.1);
}
AT(140) {
play_sound("redirect");
play_sfx_delayed("redirect", 0, false, 180);
}
FROM_TO(140, 320, 1) {
e->pos += 3 * cexp(I*(carg(e->args[1] - e->pos) + M_PI/2));
GO_TO(e, e->args[1], pow((t - 140) / 300.0, 3));
}
FROM_TO_SND("shot1_loop", 140, 280, 1 + 2 * (1 + D_Lunatic - global.diff)) {
// complex dir = cexp(I*carg(global.plr.pos - e->pos));
for(int i = 0; i < 2 - (global.diff == D_Easy); ++i) {
cmplx dir = cexp(I*(M_PI*i + M_PI/8*sin(2*(t-140)/70.0 * M_PI) + carg(e->args[1] - e->pos)));
PROJECTILE(
.proto = pp_ball,
.pos = e->pos,
.color = RGBA(0.1 + 0.5 * pow((t - 140) / 140.0, 2), 0.0, 0.8, 0.0),
.rule = accelerated,
.args = {
(-2 + (global.diff == D_Hard)) * dir,
0.02 * dir * (!i || global.diff != D_Lunatic),
},
);
}
}
AT(380) {
return ACTION_DESTROY;
}
return 1;
}
static int stage5_lightburst2(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 4, ITEM_POWER, 4);
return 1;
}
FROM_TO(0, 70, 1) {
GO_TO(e, e->pos0 + e->args[0] * 70, 0.05);
}
if(t > 200)
e->pos += e->args[0];
FROM_TO_SND("shot1_loop", 20, 170, 5) {
int i;
int c = 4+global.diff-(global.diff==D_Easy);
for(i = 0; i < c; i++) {
tsrand_fill(2);
cmplx n = cexp(I*carg(global.plr.pos-e->pos) + 2.0*I*M_PI/c*i);
PROJECTILE(
.proto = pp_bigball,
.pos = e->pos + 50*n*cexp(-1.0*I*_i*global.diff),
.color = RGB(0.3, 0, 0.7+0.3*(_i&1)),
.rule = asymptotic,
.args = {
2.5*n+0.25*global.diff*afrand(0)*cexp(2.0*I*M_PI*afrand(1)),
3
}
);
}
play_sound("shot2");
}
return 1;
}
static int stage5_superbullet(Enemy *e, int t) {
TIMER(&t);
AT(EVENT_KILLED) {
spawn_items(e->pos, ITEM_POINTS, 4, ITEM_POWER, 3);
return 1;
}
FROM_TO(0, 70, 1) {
GO_TO(e, e->pos0 + e->args[0] * 70, 0.05);
}
FROM_TO(60, 200, 1) {
cmplx n = cexp(I*M_PI*sin(_i/(8.0+global.diff)+frand()*0.1)+I*carg(global.plr.pos-e->pos));
PROJECTILE(
.proto = pp_bullet,
.pos = e->pos + 50*n,
.color = RGB(0.6, 0, 0),
.rule = asymptotic,
.args = { 2*n, 10 }
);
play_sound("shot1");
}
FROM_TO(260, 400, 1)
e->pos -= e->args[0];
return 1;
}
void stage5_events(void) {
TIMER(&global.timer);
AT(0) {
stage_start_bgm("stage5");
stage_set_voltage_thresholds(255, 480, 860, 1250);
}
FROM_TO(60, 150, 15) {
create_enemy1c(VIEWPORT_W*(_i&1)+70.0*I+50*_i*I, 400, Fairy, stage5_greeter, 3-6*(_i&1));
}
FROM_TO(270, 320, 40)
create_enemy1c(VIEWPORT_W/4+VIEWPORT_W/2*_i, 2000, BigFairy, stage5_lightburst, 2.0*I);
FROM_TO(400, 600, 10) {
tsrand_fill(2);
create_enemy3c(200.0*I*afrand(0), 500, Swirl, stage5_swirl, 4+I, 70+20*afrand(1)+200.0*I, cexp(-0.05*I));
}
FROM_TO(700, 800, 10) {
tsrand_fill(3);
create_enemy3c(VIEWPORT_W+200.0*I*afrand(0), 500, Swirl, stage5_swirl, -4+afrand(1)*I, 70+20*afrand(2)+200.0*I, cexp(0.05*I));
}
FROM_TO(870+50*(global.diff==D_Easy), 1000, 50)
create_enemy1c(VIEWPORT_W/4+VIEWPORT_W/2*(_i&1), 2000, BigFairy, stage5_limiter, I);
AT(1000)
create_enemy1c(VIEWPORT_W/2, 9000, BigFairy, stage5_laserfairy, 2.0*I);
FROM_TO(1400+100*(D_Lunatic - global.diff), 2560, 60-5*global.diff) {
tsrand_fill(2);
create_enemy1c(VIEWPORT_W+200.0*I*afrand(0), 500, Swirl, stage5_miner, -3+2.0*I*afrand(1));
}
FROM_TO(1500, 2400, 80)
create_enemy1c(VIEWPORT_W*(_i&1)+100.0*I, 300, Fairy, stage5_greeter, 3-6*(_i&1));
AT(2500) {
create_enemy1c(VIEWPORT_W/2, 2000, BigFairy, stage5_lightburst, 2.0*I);
}
FROM_TO(2200, 2600, 60-8*global.diff)
create_enemy1c(VIEWPORT_W/(6+global.diff)*_i, 200, Swirl, stage5_miner, 3.0*I);
AT(2700) {
if(global.diff > D_Easy) {
create_enemy1c(VIEWPORT_W-20+120*I, 2000, BigFairy, stage5_lightburst, -2.0);
}
}
AT(2900)
global.boss = stage5_spawn_midboss();
AT(2920) {
stage5_dialog_post_midboss();
// TODO: determine if this hack is still required with the new dialogue system
global.timer++;
}
FROM_TO(3000, 3200, 100) {
create_enemy1c(VIEWPORT_W/2 + VIEWPORT_W/6*(1-2*(_i&1)), 2000, BigFairy, stage5_lightburst2, -1+2*(_i&1) + 2.0*I);
}
FROM_TO(3300, 4000, 90-10*global.diff)
create_enemy1c(200.0*I+VIEWPORT_W*(_i&1), 1500, Fairy, stage5_superbullet, 3-6*(_i&1));
AT(3400) {
create_enemy2c(VIEWPORT_W/4, 6000, BigFairy, stage5_laserfairy, 2.0*I, 1);
create_enemy2c(VIEWPORT_W/4*3, 6000, BigFairy, stage5_laserfairy, 2.0*I, 1);
}
FROM_TO(4200, 5000, 20-3*global.diff) {
float f = frand();
create_enemy3c(
VIEWPORT_W/2+300*sin(global.frames)*cos(2*global.frames),
400,
Swirl,
stage5_swirl,
2*cexp(I*M_PI*f)+I,
60 + 100.0*I,
cexp(0.01*I*(1-2*(f<0.5)))
);
}
FROM_TO(4320, 4400, 60) {
double ofs = 32;
create_enemy1c(ofs + (VIEWPORT_W-2*ofs)*(_i&1) + VIEWPORT_H*I, 200, Swirl, stage5_miner, -I);
}
FROM_TO(4260, 5000, 60) {
create_enemy1c(VIEWPORT_W*(_i&1)+120*I, 400, Fairy, stage5_greeter, 6 * (1-2*(_i&1)) + I);
}
AT(5000) {
create_enemy1c(VIEWPORT_W/2, 2000, BigFairy, stage5_lightburst, 2.0*I);
}
FROM_TO(5030, 5060, 30) {
create_enemy1c(30.0*I+VIEWPORT_W*(_i&1), 1500, Fairy, stage5_superbullet, 2-4*(_i&1) + I);
}
AT(5180) {
create_enemy1c(VIEWPORT_W/2+100, 2000, BigFairy, stage5_lightburst2, 2.0*I - 0.25);
}
FROM_TO(5060, 5300, 60-10*global.diff) {
tsrand_fill(2);
create_enemy1c(VIEWPORT_W+200.0*I*afrand(0), 500, Swirl, stage5_miner, -3+2.0*I*afrand(1));
}
AT(5360) {
create_enemy1c(30.0*I+VIEWPORT_W, 1500, Fairy, stage5_superbullet, -2 + I);
}
AT(5390) {
create_enemy1c(30.0*I, 1500, Fairy, stage5_superbullet, 2 + I);
}
AT(5500) {
create_enemy1c(VIEWPORT_W+20 + VIEWPORT_H*0.6*I, 2000, BigFairy, stage5_lightburst, -2*I - 2);
create_enemy1c( -20 + VIEWPORT_H*0.6*I, 2000, BigFairy, stage5_lightburst, -2*I + 2);
}
AT(5600) {
enemy_kill_all(&global.enemies);
}
{
int cnt = 5;
int step = 10;
double ofs = 42*2;
FROM_TO(5620, 5620 + step*cnt-1, step) {
cmplx src1 = -ofs/4 + (-ofs/4 + _i * (VIEWPORT_H-2*ofs)/(cnt-1))*I;
cmplx src2 = (VIEWPORT_W + ofs/4) + (-ofs/4 + (cnt-_i-1) * (VIEWPORT_H-2*ofs)/(cnt-1))*I;
cmplx dst1 = ofs + ( ofs + _i * (VIEWPORT_H-2*ofs)/(cnt-1))*I;
cmplx dst2 = (VIEWPORT_W - ofs) + ( ofs + (cnt-_i-1) * (VIEWPORT_H-2*ofs)/(cnt-1))*I;
create_enemy2c(src1, 2000, Swirl, stage5_magnetto, dst1, dst2);
create_enemy2c(src2, 2000, Swirl, stage5_magnetto, dst2, dst1);
}
}
FROM_TO(6100, 6350, 60-12*global.diff) {
tsrand_fill(2);
create_enemy1c(VIEWPORT_W+200.0*I*afrand(0), 500, Swirl, stage5_miner, -3+2.0*I*afrand(1));
}
FROM_TO(6300, 6350, 50) {
create_enemy1c(VIEWPORT_W/4+VIEWPORT_W/2*!(_i&1), 2000, BigFairy, stage5_limiter, 2*I);
}
AT(6960) {
stage_unlock_bgm("stage5");
global.boss = stage5_spawn_boss();
}
AT(6980) {
stage_unlock_bgm("stage5boss");
stage5_dialog_post_boss();
}
AT(6985) {
stage_finish(GAMEOVER_SCORESCREEN);
}
}

View file

@ -0,0 +1,19 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_timeline_h
#define IGUARD_stages_stage5_timeline_h
#include "taisei.h"
#include "boss.h"
void stage5_events(void);
Boss* stage5_spawn_iku(cmplx);
#endif // IGUARD_stages_stage5_timeline_h

File diff suppressed because it is too large Load diff

View file

@ -1,26 +0,0 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_stages_stage5_events_h
#define IGUARD_stages_stage5_events_h
#include "taisei.h"
#include "boss.h"
void iku_spell_bg(Boss*, int);
void iku_atmospheric(Boss*, int);
void iku_lightning(Boss*, int);
void iku_cathode(Boss*, int);
void iku_induction(Boss*, int);
void iku_extra(Boss*, int);
void stage5_events(void);
Boss* stage5_spawn_iku(cmplx pos);
#endif // IGUARD_stages_stage5_events_h