Initial support for single-spell stages
Adapted all of the current spellcards into spellstages, which will later be used in a spell practice mode a-la IN. For now they are only accessible through the stage select menu or by specifying their ID on the command line; both available only if you built with -DTAISEI_DEBUG=1
This commit is contained in:
parent
1f6faed3fc
commit
1e6011433c
30 changed files with 758 additions and 113 deletions
21
src/boss.c
21
src/boss.c
|
@ -7,10 +7,11 @@
|
|||
|
||||
#include "boss.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Boss *create_boss(char *name, char *ani, complex pos) {
|
||||
Boss* create_boss(char *name, char *ani, complex pos) {
|
||||
Boss *buf = malloc(sizeof(Boss));
|
||||
memset(buf, 0, sizeof(Boss));
|
||||
|
||||
|
@ -190,7 +191,7 @@ void start_attack(Boss *b, Attack *a) {
|
|||
delete_lasers();
|
||||
}
|
||||
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
|
||||
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
|
||||
boss->attacks = realloc(boss->attacks, sizeof(Attack)*(++boss->acount));
|
||||
Attack *a = &boss->attacks[boss->acount-1];
|
||||
|
||||
|
@ -213,3 +214,19 @@ Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout,
|
|||
|
||||
return a;
|
||||
}
|
||||
|
||||
void boss_generic_move(Boss *b, int time) {
|
||||
if(b->current->info->pos_dest != BOSS_NOMOVE) {
|
||||
GO_TO(b, b->current->info->pos_dest, 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move) {
|
||||
if(move) {
|
||||
boss_add_attack(boss, AT_Move, "Generic Move", 1, 0, boss_generic_move, NULL)->info = info;
|
||||
}
|
||||
|
||||
Attack *a = boss_add_attack(boss, info->type, info->name, info->timeout, info->hp, info->rule, info->draw_rule);
|
||||
a->info = info;
|
||||
return a;
|
||||
}
|
||||
|
|
23
src/boss.h
23
src/boss.h
|
@ -22,6 +22,18 @@ typedef enum AttackType {
|
|||
AT_SurvivalSpell
|
||||
} AttackType;
|
||||
|
||||
typedef struct AttackInfo {
|
||||
AttackType type;
|
||||
char *name;
|
||||
float timeout;
|
||||
int hp;
|
||||
|
||||
BossRule rule;
|
||||
BossRule draw_rule;
|
||||
|
||||
// complex pos_spawn;
|
||||
complex pos_dest;
|
||||
} AttackInfo;
|
||||
|
||||
typedef struct Attack {
|
||||
char *name;
|
||||
|
@ -35,6 +47,8 @@ typedef struct Attack {
|
|||
|
||||
BossRule rule;
|
||||
BossRule draw_rule;
|
||||
|
||||
AttackInfo *info; // NULL for attacks created directly through boss_add_attack
|
||||
} Attack;
|
||||
|
||||
typedef struct Boss {
|
||||
|
@ -54,7 +68,7 @@ typedef struct Boss {
|
|||
Color *zoomcolor;
|
||||
} Boss;
|
||||
|
||||
Boss *create_boss(char *name, char *ani, complex pos);
|
||||
Boss* create_boss(char *name, char *ani, complex pos);
|
||||
void draw_boss(Boss *boss);
|
||||
void process_boss(Boss *boss);
|
||||
|
||||
|
@ -63,8 +77,13 @@ void free_attack(Attack *a);
|
|||
|
||||
void start_attack(Boss *b, Attack *a);
|
||||
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule);
|
||||
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule);
|
||||
Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move);
|
||||
|
||||
void boss_death(Boss **boss);
|
||||
|
||||
#define BOSS_DEFAULT_SPAWN_POS (VIEWPORT_W * 0.5 - I * VIEWPORT_H * 0.5)
|
||||
#define BOSS_DEFAULT_GO_POS (VIEWPORT_W * 0.5 + 200.0I)
|
||||
#define BOSS_NOMOVE (-3142-39942I)
|
||||
|
||||
#endif
|
||||
|
|
12
src/global.c
12
src/global.c
|
@ -252,10 +252,22 @@ char* difficulty_name(Difficulty diff) {
|
|||
case D_Normal: return "Normal"; break;
|
||||
case D_Hard: return "Hard"; break;
|
||||
case D_Lunatic: return "Lunatic"; break;
|
||||
case D_Extra: return "Extra"; break;
|
||||
default: return "Unknown"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void difficulty_color(Color *c, Difficulty diff) {
|
||||
switch(diff) {
|
||||
case D_Easy: c->r = 0.5; c->g = 1.0; c->b = 0.5; break;
|
||||
case D_Normal: c->r = 0.5; c->g = 0.5; c->b = 1.0; break;
|
||||
case D_Hard: c->r = 1.0; c->g = 0.5; c->b = 0.5; break;
|
||||
case D_Lunatic: c->r = 1.0; c->g = 0.5; c->b = 1.0; break;
|
||||
case D_Extra: c->r = 0.5; c->g = 1.0; c->b = 1.0; break;
|
||||
default: c->r = 0.5; c->g = 0.5; c->b = 0.5; break;
|
||||
}
|
||||
}
|
||||
|
||||
void stralloc(char **dest, const char *src) {
|
||||
if(*dest)
|
||||
free(*dest);
|
||||
|
|
|
@ -98,6 +98,7 @@ typedef struct {
|
|||
Projectile *particles;
|
||||
|
||||
int frames;
|
||||
int stageuiframes;
|
||||
int lasttime; // frame limiter
|
||||
int timer;
|
||||
int frameskip;
|
||||
|
@ -121,6 +122,8 @@ typedef struct {
|
|||
|
||||
RandomState rand_game;
|
||||
RandomState rand_visual;
|
||||
|
||||
StageInfo *stage;
|
||||
} Global;
|
||||
|
||||
extern Global global;
|
||||
|
@ -150,6 +153,7 @@ double approach(double v, double t, double d);
|
|||
double psin(double);
|
||||
bool strendswith(char *s, char *e);
|
||||
char* difficulty_name(Difficulty diff);
|
||||
void difficulty_color(Color *c, Difficulty diff);
|
||||
void stralloc(char **dest, const char *src);
|
||||
bool gamekeypressed(KeyIndex key);
|
||||
int getenvint(const char *v);
|
||||
|
|
48
src/main.c
48
src/main.c
|
@ -86,11 +86,23 @@ int run_tests(void) {
|
|||
#define MKDIR(p) mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main(int argc, char **argv) {
|
||||
if(run_tests()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if(argc >= 2 && argv[1] && !strcmp(argv[1], "dumpstages")) {
|
||||
stage_init_array();
|
||||
|
||||
for(StageInfo *stg = stages; stg->loop; ++stg) {
|
||||
printf("%i %s: %s\n", stg->id, stg->title, stg->subtitle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
init_paths();
|
||||
init_log();
|
||||
|
||||
|
@ -121,6 +133,7 @@ int main(int argc, char** argv) {
|
|||
draw_loading_screen();
|
||||
|
||||
gamepad_init();
|
||||
stage_init_array();
|
||||
|
||||
// Order DOES matter: init_global, then sfx/bgm, then load_resources.
|
||||
init_sfx();
|
||||
|
@ -135,29 +148,36 @@ int main(int argc, char** argv) {
|
|||
if(argc >= 2 && argv[1]) {
|
||||
printf("** Entering stage skip mode: Stage %d\n", atoi(argv[1]));
|
||||
|
||||
global.diff = D_Easy;
|
||||
StageInfo* stg = stage_get(atoi(argv[1]));
|
||||
|
||||
if(!stg) {
|
||||
errx(-1, "Invalid stage id");
|
||||
}
|
||||
|
||||
global.diff = stg->difficulty;
|
||||
|
||||
if(!global.diff) {
|
||||
global.diff = D_Easy;
|
||||
}
|
||||
|
||||
if(argc == 3 && argv[2]) {
|
||||
printf("** Setting difficulty to %d.\n", atoi(argv[2]));
|
||||
global.diff = atoi(argv[2]);
|
||||
}
|
||||
|
||||
StageInfo* stg = stage_get(atoi(argv[1]));
|
||||
|
||||
if(stg) {
|
||||
printf("** Entering %s.\n", stg->title);
|
||||
printf("** Entering %s.\n", stg->title);
|
||||
|
||||
do {
|
||||
global.game_over = 0;
|
||||
init_player(&global.plr);
|
||||
stg->loop();
|
||||
} while(global.game_over == GAMEOVER_RESTART);
|
||||
do {
|
||||
global.game_over = 0;
|
||||
init_player(&global.plr);
|
||||
global.stage = stg;
|
||||
stg->loop();
|
||||
} while(global.game_over == GAMEOVER_RESTART);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("** Invalid stage number. Quitting stage skip mode.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MenuData menu;
|
||||
|
|
|
@ -15,17 +15,29 @@
|
|||
|
||||
void start_game(MenuData *menu, void *arg) {
|
||||
MenuData m;
|
||||
StageInfo *info = arg;
|
||||
Difficulty stagediff;
|
||||
|
||||
init_player(&global.plr);
|
||||
|
||||
troll:
|
||||
create_difficulty_menu(&m);
|
||||
if(difficulty_menu_loop(&m) == -1)
|
||||
return;
|
||||
global.diff = stagediff = info ? info->difficulty : D_Any;
|
||||
|
||||
if(stagediff == D_Any) {
|
||||
create_difficulty_menu(&m);
|
||||
if(difficulty_menu_loop(&m) == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
create_char_menu(&m);
|
||||
if(char_menu_loop(&m) == -1)
|
||||
if(char_menu_loop(&m) == -1) {
|
||||
if(stagediff != D_Any) {
|
||||
return;
|
||||
}
|
||||
|
||||
goto troll;
|
||||
}
|
||||
|
||||
global.replay_stage = NULL;
|
||||
replay_init(&global.replay);
|
||||
|
@ -34,12 +46,14 @@ troll:
|
|||
int sht = global.plr.shot;
|
||||
|
||||
troll2:
|
||||
if(arg)
|
||||
((StageInfo*)arg)->loop();
|
||||
else {
|
||||
int i;
|
||||
for(i = 0; stages[i].loop; ++i)
|
||||
if(info) {
|
||||
global.stage = info;
|
||||
info->loop();
|
||||
} else {
|
||||
for(int i = 0; stages[i].type == STAGE_STORY; ++i) {
|
||||
global.stage = stages + i;
|
||||
stages[i].loop();
|
||||
}
|
||||
}
|
||||
|
||||
if(global.game_over == GAMEOVER_RESTART) {
|
||||
|
|
|
@ -56,6 +56,7 @@ void start_replay(MenuData *menu, void *arg) {
|
|||
continue;
|
||||
}
|
||||
|
||||
global.stage = gstg;
|
||||
gstg->loop();
|
||||
|
||||
if(global.game_over == GAMEOVER_ABORT) {
|
||||
|
@ -219,10 +220,17 @@ static void replayview_drawitem(void *n, int item, int cnt) {
|
|||
|
||||
case 4:
|
||||
a = AL_Right;
|
||||
if(rpy->numstages == 1)
|
||||
snprintf(tmp, sizeof(tmp), "Stage %i", rpy->stages[0].stage);
|
||||
else
|
||||
if(rpy->numstages == 1) {
|
||||
StageInfo *stg = stage_get(rpy->stages[0].stage);
|
||||
|
||||
if(stg) {
|
||||
snprintf(tmp, sizeof(tmp), "%s", stg->title);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "?????");
|
||||
}
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "%i stages", rpy->numstages);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,17 +15,22 @@
|
|||
|
||||
void create_stage_menu(MenuData *m) {
|
||||
char title[STGMENU_MAX_TITLE_LENGTH];
|
||||
int i;
|
||||
Difficulty lastdiff = D_Any;
|
||||
|
||||
create_menu(m);
|
||||
m->flags = MF_Abortable;
|
||||
|
||||
for(i = 0; stages[i].loop; ++i) if(!stages[i].hidden) {
|
||||
snprintf(title, STGMENU_MAX_TITLE_LENGTH, "%s", stages[i].title);
|
||||
add_menu_entry(m, title, start_game, stages+i);
|
||||
for(int i = 0; stages[i].loop; ++i) {
|
||||
if(stages[i].difficulty < lastdiff || (stages[i].difficulty && !lastdiff)) {
|
||||
add_menu_separator(m);
|
||||
}
|
||||
|
||||
snprintf(title, STGMENU_MAX_TITLE_LENGTH, "%s: %s", stages[i].title, stages[i].subtitle);
|
||||
add_menu_entry(m, title, start_game, &(stages[i]));
|
||||
|
||||
lastdiff = stages[i].difficulty;
|
||||
}
|
||||
|
||||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ typedef struct ReplayStage {
|
|||
/* BEGIN stored fields */
|
||||
|
||||
// initial game settings
|
||||
uint16_t stage;
|
||||
uint16_t stage; // must match type of StageInfo.id in replay.h
|
||||
uint32_t seed; // this also happens to be the game initiation time - and we use this property, don't break it please
|
||||
uint8_t diff;
|
||||
uint32_t points;
|
||||
|
|
256
src/stage.c
256
src/stage.c
|
@ -22,29 +22,229 @@
|
|||
#include "taisei_err.h"
|
||||
|
||||
StageInfo stages[] = {
|
||||
// id loop hidden title subtitle titleclr bosstitleclr
|
||||
{1, stage1_loop, false, "Stage 1", "Misty Lake", {1, 1, 1}, {1, 1, 1}},
|
||||
{2, stage2_loop, false, "Stage 2", "Walk Along the Border", {1, 1, 1}, {1, 1, 1}},
|
||||
{3, stage3_loop, false, "Stage 3", "Through the Tunnel of Light", {0, 0, 0}, {0, 0, 0}},
|
||||
{4, stage4_loop, false, "Stage 4", "Forgotten Mansion", {0, 0, 0}, {1, 1, 1}},
|
||||
{5, stage5_loop, false, "Stage 5", "Climbing the Tower of Babel", {1, 1, 1}, {1, 1, 1}},
|
||||
{6, stage6_loop, false, "Stage 6", "Roof of the World", {1, 1, 1}, {1, 1, 1}},
|
||||
//
|
||||
// ids must be unique
|
||||
// they don't necessarily have to be human-readable or ordered
|
||||
// they're basically there just for replays, so don't change the already enstabilished ones unless you must
|
||||
//
|
||||
|
||||
//
|
||||
// Story stages
|
||||
//
|
||||
|
||||
// id loop type title subtitle titleclr bosstitleclr spell difficulty
|
||||
{1, stage1_loop, STAGE_STORY, "Stage 1", "Misty Lake", {1, 1, 1}, {1, 1, 1}, NULL, D_Any},
|
||||
{2, stage2_loop, STAGE_STORY, "Stage 2", "Walk Along the Border", {1, 1, 1}, {1, 1, 1}, NULL, D_Any},
|
||||
{3, stage3_loop, STAGE_STORY, "Stage 3", "Through the Tunnel of Light", {0, 0, 0}, {0, 0, 0}, NULL, D_Any},
|
||||
{4, stage4_loop, STAGE_STORY, "Stage 4", "Forgotten Mansion", {0, 0, 0}, {1, 1, 1}, NULL, D_Any},
|
||||
{5, stage5_loop, STAGE_STORY, "Stage 5", "Climbing the Tower of Babel", {1, 1, 1}, {1, 1, 1}, NULL, D_Any},
|
||||
{6, stage6_loop, STAGE_STORY, "Stage 6", "Roof of the World", {1, 1, 1}, {1, 1, 1}, NULL, D_Any},
|
||||
|
||||
//
|
||||
// Spell practice stages
|
||||
//
|
||||
// subtitles for those are generated later by stage_init_array()
|
||||
//
|
||||
|
||||
#define S STAGE_SPELL_BIT
|
||||
// Freeze Sign ~ Perfect Freeze
|
||||
{S| 0, stage1_spellpractice_loop, STAGE_SPELL, "Spell 1", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Easy},
|
||||
{S| 1, stage1_spellpractice_loop, STAGE_SPELL, "Spell 2", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Normal},
|
||||
{S| 2, stage1_spellpractice_loop, STAGE_SPELL, "Spell 3", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Hard},
|
||||
{S| 3, stage1_spellpractice_loop, STAGE_SPELL, "Spell 4", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+0, D_Lunatic},
|
||||
|
||||
// Freeze Sign ~ Crystal Rain
|
||||
{S| 4, stage1_spellpractice_loop, STAGE_SPELL, "Spell 5", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+1, D_Easy},
|
||||
{S| 5, stage1_spellpractice_loop, STAGE_SPELL, "Spell 6", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+1, D_Normal},
|
||||
{S| 6, stage1_spellpractice_loop, STAGE_SPELL, "Spell 7", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+1, D_Hard},
|
||||
{S| 7, stage1_spellpractice_loop, STAGE_SPELL, "Spell 8", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+1, D_Lunatic},
|
||||
|
||||
// Doom Sign ~ Icicle Fall
|
||||
{S| 8, stage1_spellpractice_loop, STAGE_SPELL, "Spell 9", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+2, D_Easy},
|
||||
{S| 9, stage1_spellpractice_loop, STAGE_SPELL, "Spell 10", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+2, D_Normal},
|
||||
{S| 10, stage1_spellpractice_loop, STAGE_SPELL, "Spell 11", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+2, D_Hard},
|
||||
{S| 11, stage1_spellpractice_loop, STAGE_SPELL, "Spell 12", NULL, {1, 1, 1}, {1, 1, 1}, stage1_spells+2, D_Lunatic},
|
||||
|
||||
// Shard ~ Amulet of Harm
|
||||
{S| 12, stage2_spellpractice_loop, STAGE_SPELL, "Spell 13", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+0, D_Easy},
|
||||
{S| 13, stage2_spellpractice_loop, STAGE_SPELL, "Spell 14", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+0, D_Normal},
|
||||
{S| 14, stage2_spellpractice_loop, STAGE_SPELL, "Spell 15", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+0, D_Hard},
|
||||
{S| 15, stage2_spellpractice_loop, STAGE_SPELL, "Spell 16", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+0, D_Lunatic},
|
||||
|
||||
// Lottery Sign ~ Bad Pick
|
||||
{S| 16, stage2_spellpractice_loop, STAGE_SPELL, "Spell 17", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+1, D_Easy},
|
||||
{S| 17, stage2_spellpractice_loop, STAGE_SPELL, "Spell 18", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+1, D_Normal},
|
||||
{S| 18, stage2_spellpractice_loop, STAGE_SPELL, "Spell 19", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+1, D_Hard},
|
||||
{S| 19, stage2_spellpractice_loop, STAGE_SPELL, "Spell 20", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+1, D_Lunatic},
|
||||
|
||||
// Lottery Sign ~ Wheel of Fortune
|
||||
{S| 20, stage2_spellpractice_loop, STAGE_SPELL, "Spell 21", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+2, D_Easy},
|
||||
{S| 21, stage2_spellpractice_loop, STAGE_SPELL, "Spell 22", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+2, D_Normal},
|
||||
{S| 22, stage2_spellpractice_loop, STAGE_SPELL, "Spell 23", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+2, D_Hard},
|
||||
{S| 23, stage2_spellpractice_loop, STAGE_SPELL, "Spell 24", NULL, {1, 1, 1}, {1, 1, 1}, stage2_spells+2, D_Lunatic},
|
||||
|
||||
// Venom Sign ~ Deadly Dance
|
||||
{S| 24, stage3_spellpractice_loop, STAGE_SPELL, "Spell 25", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+0, D_Easy},
|
||||
{S| 25, stage3_spellpractice_loop, STAGE_SPELL, "Spell 26", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+0, D_Normal},
|
||||
{S| 26, stage3_spellpractice_loop, STAGE_SPELL, "Spell 27", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+0, D_Hard},
|
||||
{S| 27, stage3_spellpractice_loop, STAGE_SPELL, "Spell 28", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+0, D_Lunatic},
|
||||
|
||||
// Venom Sign ~ Acid Rain
|
||||
{S| 28, stage3_spellpractice_loop, STAGE_SPELL, "Spell 29", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+1, D_Hard},
|
||||
{S| 29, stage3_spellpractice_loop, STAGE_SPELL, "Spell 30", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+1, D_Lunatic},
|
||||
|
||||
// Firefly Sign ~ Moonlight Rocket
|
||||
{S| 30, stage3_spellpractice_loop, STAGE_SPELL, "Spell 31", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+2, D_Easy},
|
||||
{S| 31, stage3_spellpractice_loop, STAGE_SPELL, "Spell 32", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+2, D_Normal},
|
||||
{S| 32, stage3_spellpractice_loop, STAGE_SPELL, "Spell 33", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+2, D_Hard},
|
||||
{S| 33, stage3_spellpractice_loop, STAGE_SPELL, "Spell 34", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+2, D_Lunatic},
|
||||
|
||||
// Light Source ~ Wriggle Night Ignite
|
||||
{S| 34, stage3_spellpractice_loop, STAGE_SPELL, "Spell 35", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+3, D_Easy},
|
||||
{S| 35, stage3_spellpractice_loop, STAGE_SPELL, "Spell 36", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+3, D_Normal},
|
||||
{S| 36, stage3_spellpractice_loop, STAGE_SPELL, "Spell 37", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+3, D_Hard},
|
||||
{S| 37, stage3_spellpractice_loop, STAGE_SPELL, "Spell 38", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+3, D_Lunatic},
|
||||
|
||||
// Bug Sign ~ Phosphaenus Hemipterus
|
||||
{S| 38, stage3_spellpractice_loop, STAGE_SPELL, "Spell 39", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+4, D_Easy},
|
||||
{S| 39, stage3_spellpractice_loop, STAGE_SPELL, "Spell 40", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+4, D_Normal},
|
||||
{S| 40, stage3_spellpractice_loop, STAGE_SPELL, "Spell 41", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+4, D_Hard},
|
||||
{S| 41, stage3_spellpractice_loop, STAGE_SPELL, "Spell 42", NULL, {0, 0, 0}, {0, 0, 0}, stage3_spells+4, D_Lunatic},
|
||||
|
||||
// Bloodless ~ Gate of Walachia
|
||||
{S| 42, stage4_spellpractice_loop, STAGE_SPELL, "Spell 43", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+0, D_Easy},
|
||||
{S| 43, stage4_spellpractice_loop, STAGE_SPELL, "Spell 44", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+0, D_Normal},
|
||||
{S| 44, stage4_spellpractice_loop, STAGE_SPELL, "Spell 45", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+0, D_Hard},
|
||||
{S| 45, stage4_spellpractice_loop, STAGE_SPELL, "Spell 46", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+0, D_Lunatic},
|
||||
|
||||
// Bloodless ~ Dry Fountain
|
||||
{S| 46, stage4_spellpractice_loop, STAGE_SPELL, "Spell 47", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+1, D_Easy},
|
||||
{S| 47, stage4_spellpractice_loop, STAGE_SPELL, "Spell 48", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+1, D_Normal},
|
||||
|
||||
// Bloodless ~ Red Spike
|
||||
{S| 48, stage4_spellpractice_loop, STAGE_SPELL, "Spell 49", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+2, D_Hard},
|
||||
{S| 49, stage4_spellpractice_loop, STAGE_SPELL, "Spell 50", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+2, D_Lunatic},
|
||||
|
||||
// Limit ~ Animate Wall
|
||||
{S| 50, stage4_spellpractice_loop, STAGE_SPELL, "Spell 51", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+3, D_Easy},
|
||||
{S| 51, stage4_spellpractice_loop, STAGE_SPELL, "Spell 52", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+3, D_Normal},
|
||||
|
||||
// Summoning ~ Demon Wall
|
||||
{S| 52, stage4_spellpractice_loop, STAGE_SPELL, "Spell 53", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+4, D_Hard},
|
||||
{S| 53, stage4_spellpractice_loop, STAGE_SPELL, "Spell 54", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+4, D_Lunatic},
|
||||
|
||||
// Power Sign ~ Blow the Walls
|
||||
{S| 54, stage4_spellpractice_loop, STAGE_SPELL, "Spell 55", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+5, D_Easy},
|
||||
{S| 55, stage4_spellpractice_loop, STAGE_SPELL, "Spell 56", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+5, D_Normal},
|
||||
{S| 56, stage4_spellpractice_loop, STAGE_SPELL, "Spell 57", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+5, D_Hard},
|
||||
{S| 57, stage4_spellpractice_loop, STAGE_SPELL, "Spell 58", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+5, D_Lunatic},
|
||||
|
||||
// Fear Sign ~ Bloody Danmaku
|
||||
{S| 58, stage4_spellpractice_loop, STAGE_SPELL, "Spell 59", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+6, D_Hard},
|
||||
{S| 59, stage4_spellpractice_loop, STAGE_SPELL, "Spell 60", NULL, {1, 1, 1}, {1, 1, 1}, stage4_spells+6, D_Lunatic},
|
||||
|
||||
// High Voltage ~ Atmospheric Discharge
|
||||
{S| 60, stage5_spellpractice_loop, STAGE_SPELL, "Spell 61", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+0, D_Easy},
|
||||
{S| 61, stage5_spellpractice_loop, STAGE_SPELL, "Spell 62", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+0, D_Normal},
|
||||
{S| 62, stage5_spellpractice_loop, STAGE_SPELL, "Spell 63", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+0, D_Hard},
|
||||
{S| 63, stage5_spellpractice_loop, STAGE_SPELL, "Spell 64", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+0, D_Lunatic},
|
||||
|
||||
// Charge Sign ~ Artificial Lightning
|
||||
{S| 64, stage5_spellpractice_loop, STAGE_SPELL, "Spell 65", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+1, D_Easy},
|
||||
{S| 65, stage5_spellpractice_loop, STAGE_SPELL, "Spell 66", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+1, D_Normal},
|
||||
{S| 66, stage5_spellpractice_loop, STAGE_SPELL, "Spell 67", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+1, D_Hard},
|
||||
{S| 67, stage5_spellpractice_loop, STAGE_SPELL, "Spell 68", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+1, D_Lunatic},
|
||||
|
||||
// Spark Sign ~ Natural Cathode
|
||||
{S| 68, stage5_spellpractice_loop, STAGE_SPELL, "Spell 69", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+2, D_Easy},
|
||||
{S| 69, stage5_spellpractice_loop, STAGE_SPELL, "Spell 70", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+2, D_Normal},
|
||||
{S| 70, stage5_spellpractice_loop, STAGE_SPELL, "Spell 71", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+2, D_Hard},
|
||||
{S| 71, stage5_spellpractice_loop, STAGE_SPELL, "Spell 72", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+2, D_Lunatic},
|
||||
|
||||
// Current Sign ~ Induction
|
||||
{S| 72, stage5_spellpractice_loop, STAGE_SPELL, "Spell 73", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+3, D_Easy},
|
||||
{S| 73, stage5_spellpractice_loop, STAGE_SPELL, "Spell 74", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+3, D_Normal},
|
||||
{S| 74, stage5_spellpractice_loop, STAGE_SPELL, "Spell 75", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+3, D_Hard},
|
||||
{S| 75, stage5_spellpractice_loop, STAGE_SPELL, "Spell 76", NULL, {1, 1, 1}, {1, 1, 1}, stage5_spells+3, D_Lunatic},
|
||||
|
||||
// Newton Sign ~ 2.5 Laws of Movement
|
||||
{S| 76, stage6_spellpractice_loop, STAGE_SPELL, "Spell 77", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+0, D_Easy},
|
||||
{S| 77, stage6_spellpractice_loop, STAGE_SPELL, "Spell 78", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+0, D_Normal},
|
||||
{S| 78, stage6_spellpractice_loop, STAGE_SPELL, "Spell 79", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+0, D_Hard},
|
||||
{S| 79, stage6_spellpractice_loop, STAGE_SPELL, "Spell 80", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+0, D_Lunatic},
|
||||
|
||||
// Maxwell Sign ~ Wave Theory
|
||||
{S| 80, stage6_spellpractice_loop, STAGE_SPELL, "Spell 81", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+1, D_Easy},
|
||||
{S| 81, stage6_spellpractice_loop, STAGE_SPELL, "Spell 82", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+1, D_Normal},
|
||||
{S| 82, stage6_spellpractice_loop, STAGE_SPELL, "Spell 83", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+1, D_Hard},
|
||||
{S| 83, stage6_spellpractice_loop, STAGE_SPELL, "Spell 84", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+1, D_Lunatic},
|
||||
|
||||
// Eigenstate ~ Many-World Interpretation
|
||||
{S| 84, stage6_spellpractice_loop, STAGE_SPELL, "Spell 85", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+2, D_Easy},
|
||||
{S| 85, stage6_spellpractice_loop, STAGE_SPELL, "Spell 86", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+2, D_Normal},
|
||||
{S| 86, stage6_spellpractice_loop, STAGE_SPELL, "Spell 87", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+2, D_Hard},
|
||||
{S| 87, stage6_spellpractice_loop, STAGE_SPELL, "Spell 88", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+2, D_Lunatic},
|
||||
|
||||
// Ricci Sign ~ Space Time Curvature
|
||||
{S| 88, stage6_spellpractice_loop, STAGE_SPELL, "Spell 89", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+3, D_Easy},
|
||||
{S| 89, stage6_spellpractice_loop, STAGE_SPELL, "Spell 90", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+3, D_Normal},
|
||||
{S| 90, stage6_spellpractice_loop, STAGE_SPELL, "Spell 91", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+3, D_Hard},
|
||||
{S| 91, stage6_spellpractice_loop, STAGE_SPELL, "Spell 92", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+3, D_Lunatic},
|
||||
|
||||
// LHC ~ Higgs Boson Uncovered
|
||||
{S| 92, stage6_spellpractice_loop, STAGE_SPELL, "Spell 93", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+4, D_Easy},
|
||||
{S| 93, stage6_spellpractice_loop, STAGE_SPELL, "Spell 94", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+4, D_Normal},
|
||||
{S| 94, stage6_spellpractice_loop, STAGE_SPELL, "Spell 95", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+4, D_Hard},
|
||||
{S| 95, stage6_spellpractice_loop, STAGE_SPELL, "Spell 96", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+4, D_Lunatic},
|
||||
|
||||
// Tower of Truth ~ Theory of Everything
|
||||
{S| 96, stage6_spellpractice_loop, STAGE_SPELL, "Spell 97", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Easy},
|
||||
{S| 97, stage6_spellpractice_loop, STAGE_SPELL, "Spell 98", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Normal},
|
||||
{S| 98, stage6_spellpractice_loop, STAGE_SPELL, "Spell 99", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Hard},
|
||||
{S| 99, stage6_spellpractice_loop, STAGE_SPELL, "Spell 100", NULL, {1, 1, 1}, {1, 1, 1}, stage6_spells+5, D_Lunatic},
|
||||
#undef S
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
void stage_init_array(void) {
|
||||
for(int i = 0; stages[i].loop; ++i) {
|
||||
if(stages[i].type == STAGE_SPELL) {
|
||||
char *s, *postfix = difficulty_name(stages[i].difficulty);
|
||||
|
||||
// note: never free()'d
|
||||
stages[i].subtitle = s = malloc(strlen(postfix) + strlen(stages[i].spell->name) + 4);
|
||||
strcpy(s, stages[i].spell->name);
|
||||
strcat(s, " ~ ");
|
||||
strcat(s, postfix);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if(stages[i].type == STAGE_SPELL && !(stages[i].id & STAGE_SPELL_BIT)) {
|
||||
errx(-1, "Spell stage has an ID without the spell bit set: %u", stages[i].id);
|
||||
}
|
||||
|
||||
for(int j = 0; stages[j].loop; ++j) {
|
||||
if(i != j && stages[i].id == stages[j].id) {
|
||||
errx(-1, "Duplicate ID in stages array: %u", stages[i].id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This returns the stage BY ID, not by the array index!
|
||||
StageInfo* stage_get(int n) {
|
||||
int i;
|
||||
for(i = 0; stages[i].loop; ++i)
|
||||
if(stages[i].id == n)
|
||||
return &(stages[i]);
|
||||
StageInfo* stage_get(uint16_t n) {
|
||||
for(StageInfo *stg = stages; stg->loop; ++stg)
|
||||
if(stg->id == n)
|
||||
return stg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stage_start(void) {
|
||||
global.timer = 0;
|
||||
global.frames = 0;
|
||||
global.stageuiframes = 0;
|
||||
global.game_over = 0;
|
||||
global.nostagebg = false;
|
||||
global.shake_view = 0;
|
||||
|
@ -191,14 +391,9 @@ void draw_hud(void) {
|
|||
glTranslatef((SCREEN_W - 615) * 0.25, 20, 0);
|
||||
glScalef(0.6, 0.6, 0);
|
||||
|
||||
float b = 0.5;
|
||||
|
||||
switch(global.diff) {
|
||||
case D_Easy: glColor4f(b, 1, b, 0.7); break;
|
||||
case D_Normal: glColor4f(b, b, 1, 0.7); break;
|
||||
case D_Hard: glColor4f(1, b, b, 0.7); break;
|
||||
case D_Lunatic: glColor4f(1, b, 1, 0.7); break;
|
||||
}
|
||||
Color clr;
|
||||
difficulty_color(&clr, global.diff);
|
||||
glColor4f(clr.r, clr.g, clr.b, 0.7f);
|
||||
|
||||
diff = difficulty_name(global.diff);
|
||||
draw_text(AL_Center, 1, 1, diff, _fonts.mainmenu);
|
||||
|
@ -434,6 +629,7 @@ void stage_logic(int time) {
|
|||
page_dialog(&global.dialog);
|
||||
|
||||
global.frames++;
|
||||
global.stageuiframes++;
|
||||
|
||||
if(!global.dialog && !global.boss)
|
||||
global.timer++;
|
||||
|
@ -447,7 +643,7 @@ void stage_logic(int time) {
|
|||
set_transition(TransFadeBlack, FADE_TIME, FADE_TIME*2);
|
||||
}
|
||||
|
||||
if(global.timer >= time)
|
||||
if(time && global.timer >= time)
|
||||
global.game_over = GAMEOVER_WIN;
|
||||
|
||||
// BGM handling
|
||||
|
@ -476,13 +672,16 @@ void stage_end(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, StageRule event, ShaderRule *shaderrules, int endtime) {
|
||||
void stage_loop(StageRule start, StageRule end, StageRule draw, StageRule event, ShaderRule *shaderrules, int endtime) {
|
||||
if(global.game_over == GAMEOVER_WIN) {
|
||||
global.game_over = 0;
|
||||
} else if(global.game_over) {
|
||||
return;
|
||||
}
|
||||
|
||||
// I really want to separate all of the game state from the global struct sometime
|
||||
StageInfo *info = global.stage;
|
||||
|
||||
uint32_t seed = (uint32_t)time(0);
|
||||
tsrand_switch(&global.rand_game);
|
||||
tsrand_seed_p(&global.rand_game, seed);
|
||||
|
@ -532,11 +731,19 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw,
|
|||
|
||||
start();
|
||||
|
||||
if(info->type == STAGE_SPELL) {
|
||||
endtime = 0;
|
||||
}
|
||||
|
||||
while(global.game_over <= 0) {
|
||||
if(!global.boss && !global.dialog)
|
||||
event();
|
||||
|
||||
((global.replaymode == REPLAY_PLAY)? replay_input : stage_input)();
|
||||
if(!endtime && info->type == STAGE_SPELL && !global.boss) {
|
||||
endtime = global.timer + 60;
|
||||
}
|
||||
|
||||
((global.replaymode == REPLAY_PLAY) ? replay_input : stage_input)();
|
||||
replay_stage_check_desync(global.replay_stage, global.frames, (tsrand() ^ global.plr.points) & 0xFFFF, global.replaymode);
|
||||
|
||||
stage_logic(endtime);
|
||||
|
@ -571,6 +778,7 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw,
|
|||
end();
|
||||
stage_end();
|
||||
tsrand_switch(&global.rand_visual);
|
||||
global.stage = NULL;
|
||||
}
|
||||
|
||||
void draw_title(int t, StageInfo *info, Alignment al, int x, int y, const char *text, TTF_Font *font, Color *color) {
|
||||
|
@ -605,7 +813,7 @@ void draw_title(int t, StageInfo *info, Alignment al, int x, int y, const char *
|
|||
}
|
||||
|
||||
void draw_stage_title(StageInfo *info) {
|
||||
int t = global.frames;
|
||||
int t = global.stageuiframes;
|
||||
|
||||
draw_title(t, info, AL_Center, VIEWPORT_W/2, VIEWPORT_H/2-40, info->title, _fonts.mainmenu, &info->titleclr);
|
||||
draw_title(t, info, AL_Center, VIEWPORT_W/2, VIEWPORT_H/2, info->subtitle, _fonts.standard, &info->titleclr);
|
||||
|
|
44
src/stage.h
44
src/stage.h
|
@ -18,13 +18,16 @@
|
|||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <projectile.h>
|
||||
#include "projectile.h"
|
||||
#include "boss.h"
|
||||
|
||||
typedef enum {
|
||||
D_Easy = 1,
|
||||
D_Any = 0,
|
||||
D_Easy,
|
||||
D_Normal,
|
||||
D_Hard,
|
||||
D_Lunatic
|
||||
D_Lunatic,
|
||||
D_Extra // reserved for later
|
||||
} Difficulty;
|
||||
|
||||
#define TIMER(ptr) int *__timep = ptr; int _i = 0, _ni = 0; _i = _ni = _i;
|
||||
|
@ -40,35 +43,48 @@ typedef enum {
|
|||
typedef void (*StageRule)(void);
|
||||
typedef void (*ShaderRule)(int);
|
||||
|
||||
// highest bit of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
|
||||
#define STAGE_SPELL_BIT 0x8000
|
||||
|
||||
typedef enum StageType {
|
||||
STAGE_STORY = 1,
|
||||
STAGE_EXTRA,
|
||||
STAGE_SPELL,
|
||||
} StageType;
|
||||
|
||||
typedef struct StageInfo {
|
||||
int id;
|
||||
uint16_t id; // must match type of ReplayStage.stage in replay.h
|
||||
StageRule loop;
|
||||
bool hidden;
|
||||
StageType type;
|
||||
char *title;
|
||||
char *subtitle;
|
||||
|
||||
Color titleclr;
|
||||
Color bosstitleclr;
|
||||
|
||||
AttackInfo *spell;
|
||||
Difficulty difficulty;
|
||||
} StageInfo;
|
||||
|
||||
extern StageInfo stages[];
|
||||
StageInfo* stage_get(int);
|
||||
StageInfo* stage_get(uint16_t);
|
||||
void stage_init_array(void);
|
||||
|
||||
void stage_loop(StageInfo *info, StageRule start, StageRule end, StageRule draw, StageRule event, ShaderRule *shaderrules, int endtime);
|
||||
void stage_loop(StageRule start, StageRule end, StageRule draw, StageRule event, ShaderRule *shaderrules, int endtime);
|
||||
|
||||
void apply_bg_shaders(ShaderRule *shaderrules);
|
||||
|
||||
void draw_stage_title(StageInfo *info);
|
||||
void draw_hud(void);
|
||||
|
||||
void stage1_loop(void);
|
||||
void stage2_loop(void);
|
||||
void stage3_loop(void);
|
||||
void stage4_loop(void);
|
||||
void stage5_loop(void);
|
||||
void stage6_loop(void);
|
||||
|
||||
void stage_pause(void);
|
||||
void stage_gameover(void);
|
||||
|
||||
#include "stages/stage1.h"
|
||||
#include "stages/stage2.h"
|
||||
#include "stages/stage3.h"
|
||||
#include "stages/stage4.h"
|
||||
#include "stages/stage5.h"
|
||||
#include "stages/stage6.h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,17 @@
|
|||
|
||||
static Stage3D bgcontext;
|
||||
|
||||
void cirno_perfect_freeze(Boss*, int);
|
||||
void cirno_crystal_rain(Boss*, int);
|
||||
void cirno_icicle_fall(Boss*, int);
|
||||
void cirno_pfreeze_bg(Boss*, int);
|
||||
|
||||
AttackInfo stage1_spells[] = {
|
||||
{AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 32, 20000, cirno_perfect_freeze, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0I},
|
||||
{AT_Spellcard, "Freeze Sign ~ Crystal Rain", 28, 28000, cirno_crystal_rain, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0I},
|
||||
{AT_Spellcard, "Doom Sign ~ Icicle Fall", 35, 40000, cirno_icicle_fall, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0I},
|
||||
};
|
||||
|
||||
Dialog *stage1_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/cirno");
|
||||
|
||||
|
@ -210,7 +221,7 @@ Boss *create_cirno_mid(void) {
|
|||
Boss* cirno = create_boss("Cirno", "cirno", VIEWPORT_W + 220 + 30.0I);
|
||||
boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro, NULL);
|
||||
boss_add_attack(cirno, AT_Normal, "Icy Storm", 20, 20000, cirno_icy, NULL);
|
||||
boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 32, 20000, cirno_perfect_freeze, cirno_pfreeze_bg);
|
||||
boss_add_attack_from_info(cirno, stage1_spells+0, false);
|
||||
|
||||
start_attack(cirno, cirno->attacks);
|
||||
return cirno;
|
||||
|
@ -350,9 +361,9 @@ Boss *create_cirno(void) {
|
|||
Boss* cirno = create_boss("Cirno", "cirno", -230 + 100.0I);
|
||||
boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro_boss, NULL);
|
||||
boss_add_attack(cirno, AT_Normal, "Iceplosion 0", 20, 20000, cirno_iceplosion0, NULL);
|
||||
boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Crystal Rain", 28, 28000, cirno_crystal_rain, cirno_pfreeze_bg);
|
||||
boss_add_attack_from_info(cirno, stage1_spells+1, false);
|
||||
boss_add_attack(cirno, AT_Normal, "Iceplosion 1", 20, 20000, cirno_iceplosion1, NULL);
|
||||
boss_add_attack(cirno, AT_Spellcard, "Doom Sign ~ Icicle Fall", 35, 40000, cirno_icicle_fall, cirno_pfreeze_bg);
|
||||
boss_add_attack_from_info(cirno, stage1_spells+2, false);
|
||||
|
||||
start_attack(cirno, cirno->attacks);
|
||||
return cirno;
|
||||
|
@ -676,5 +687,21 @@ void stage1_end(void) {
|
|||
|
||||
void stage1_loop(void) {
|
||||
ShaderRule list[] = { stage1_fog, NULL };
|
||||
stage_loop(stage_get(1), stage1_start, stage1_end, stage1_draw, stage1_events, list, 5200);
|
||||
stage_loop(stage1_start, stage1_end, stage1_draw, stage1_events, list, 5200);
|
||||
}
|
||||
|
||||
void stage1_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
Boss* cirno = create_boss("Cirno", "cirno", BOSS_DEFAULT_SPAWN_POS);
|
||||
boss_add_attack_from_info(cirno, global.stage->spell, true);
|
||||
start_attack(cirno, cirno->attacks);
|
||||
global.boss = cirno;
|
||||
}
|
||||
}
|
||||
|
||||
void stage1_spellpractice_loop(void) {
|
||||
ShaderRule list[] = { stage1_fog, NULL };
|
||||
stage_loop(stage1_start, stage1_end, stage1_draw, stage1_spellpractice_events, list, 0);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
#ifndef STAGE1_H
|
||||
#define STAGE1_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage1_loop(void);
|
||||
void stage1_spellpractice_loop(void);
|
||||
|
||||
extern AttackInfo stage1_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -161,5 +161,23 @@ void stage2_draw(void) {
|
|||
|
||||
void stage2_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage2_fog, stage2_bloom, NULL };
|
||||
stage_loop(stage_get(2), stage2_start, stage2_end, stage2_draw, stage2_events, shaderrules, 5240);
|
||||
stage_loop(stage2_start, stage2_end, stage2_draw, stage2_events, shaderrules, 5240);
|
||||
}
|
||||
|
||||
void stage2_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
skip_background_anim(&bgcontext, stage2_draw, 180, &global.frames, NULL);
|
||||
|
||||
Boss* hina = create_boss("Kagiyama Hina", "hina", BOSS_DEFAULT_SPAWN_POS);
|
||||
boss_add_attack_from_info(hina, global.stage->spell, true);
|
||||
start_attack(hina, hina->attacks);
|
||||
global.boss = hina;
|
||||
}
|
||||
}
|
||||
|
||||
void stage2_spellpractice_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage2_fog, stage2_bloom, NULL };
|
||||
stage_loop(stage2_start, stage2_end, stage2_draw, stage2_spellpractice_events, shaderrules, 0);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
#ifndef STAGE2_H
|
||||
#define STAGE2_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage2_loop(void);
|
||||
void stage2_spellpractice_loop(void);
|
||||
|
||||
extern AttackInfo stage2_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,17 @@
|
|||
#include "stage.h"
|
||||
#include "enemy.h"
|
||||
|
||||
void hina_spell_bg(Boss*, int);
|
||||
void hina_amulet(Boss*, int);
|
||||
void hina_bad_pick(Boss*, int);
|
||||
void hina_wheel(Boss*, int);
|
||||
|
||||
AttackInfo stage2_spells[] = {
|
||||
{AT_Spellcard, "Shard ~ Amulet of Harm", 26, 25000, hina_amulet, hina_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Lottery Sign ~ Bad Pick", 30, 36000, hina_bad_pick, hina_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Lottery Sign ~ Wheel of Fortune", 20, 36000, hina_wheel, hina_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
};
|
||||
|
||||
Dialog *stage2_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/hina");
|
||||
|
||||
|
@ -396,10 +407,10 @@ Boss *create_hina(void) {
|
|||
Boss* hina = create_boss("Kagiyama Hina", "hina", VIEWPORT_W + 150 + 100.0I);
|
||||
boss_add_attack(hina, AT_Move, "Introduction", 2, 0, hina_intro, NULL);
|
||||
boss_add_attack(hina, AT_Normal, "Cards1", 20, 15000, hina_cards1, NULL);
|
||||
boss_add_attack(hina, AT_Spellcard, "Shard ~ Amulet of Harm", 26, 25000, hina_amulet, hina_spell_bg);
|
||||
boss_add_attack_from_info(hina, stage2_spells+0, false);
|
||||
boss_add_attack(hina, AT_Normal, "Cards2", 17, 15000, hina_cards2, NULL);
|
||||
boss_add_attack(hina, AT_Spellcard, "Lottery Sign ~ Bad Pick", 30, 36000, hina_bad_pick, hina_spell_bg);
|
||||
boss_add_attack(hina, AT_Spellcard, "Lottery Sign ~ Wheel of Fortune", 20, 36000, hina_wheel, hina_spell_bg);
|
||||
boss_add_attack_from_info(hina, stage2_spells+1, false);
|
||||
boss_add_attack_from_info(hina, stage2_spells+2, false);
|
||||
|
||||
start_attack(hina, hina->attacks);
|
||||
return hina;
|
||||
|
|
|
@ -68,7 +68,7 @@ void stage3_bg_tunnel_draw(Vector pos) {
|
|||
*/
|
||||
draw_quad();
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
@ -281,5 +281,29 @@ void stage3_draw(void) {
|
|||
|
||||
void stage3_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage3_fog, stage3_tunnel, NULL };
|
||||
stage_loop(stage_get(3), stage3_start, stage3_end, stage3_draw, stage3_events, shaderrules, 5700);
|
||||
stage_loop(stage3_start, stage3_end, stage3_draw, stage3_events, shaderrules, 5700);
|
||||
}
|
||||
|
||||
void stage3_mid_spellbg(Boss*, int t);
|
||||
|
||||
void stage3_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
if(global.stage->spell->draw_rule == stage3_mid_spellbg) {
|
||||
skip_background_anim(&bgcontext, stage3_draw, 2800, &global.timer, NULL);
|
||||
global.boss = create_boss("Scuttle", "scuttle", BOSS_DEFAULT_SPAWN_POS);
|
||||
} else {
|
||||
skip_background_anim(&bgcontext, stage3_draw, 5300, &global.timer, NULL);
|
||||
global.boss = create_boss("Wriggle EX", "wriggleex", BOSS_DEFAULT_SPAWN_POS);
|
||||
}
|
||||
|
||||
boss_add_attack_from_info(global.boss, global.stage->spell, true);
|
||||
start_attack(global.boss, global.boss->attacks);
|
||||
}
|
||||
}
|
||||
|
||||
void stage3_spellpractice_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage3_fog, stage3_tunnel, NULL };
|
||||
stage_loop(stage3_start, stage3_end, stage3_draw, stage3_spellpractice_events, shaderrules, 0);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
#ifndef STAGE3_H
|
||||
#define STAGE3_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage3_loop(void);
|
||||
void stage3_spellpractice_loop(void);
|
||||
|
||||
extern AttackInfo stage3_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,22 @@
|
|||
#include "stage.h"
|
||||
#include "enemy.h"
|
||||
|
||||
void stage3_mid_spellbg(Boss*, int t);
|
||||
void stage3_boss_spellbg(Boss*, int t);
|
||||
void stage3_mid_a1(Boss*, int t);
|
||||
void stage3_mid_a2(Boss*, int t);
|
||||
void stage3_boss_a1(Boss*, int t);
|
||||
void stage3_boss_a2(Boss*, int t);
|
||||
void stage3_boss_a3(Boss*, int t);
|
||||
|
||||
AttackInfo stage3_spells[] = {
|
||||
{AT_Spellcard, "Venom Sign ~ Deadly Dance", 25, 25000, stage3_mid_a1, stage3_mid_spellbg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Venom Sign ~ Acid Rain", 20, 23000, stage3_mid_a2, stage3_mid_spellbg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Firefly Sign ~ Moonlight Rocket", 30, 20000, stage3_boss_a1, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Light Source ~ Wriggle Night Ignite", 25, 40000, stage3_boss_a2, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Bug Sign ~ Phosphaenus Hemipterus", 35, 30000, stage3_boss_a3, stage3_boss_spellbg, BOSS_DEFAULT_GO_POS},
|
||||
};
|
||||
|
||||
Dialog *stage3_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/wriggle");
|
||||
|
||||
|
@ -429,9 +445,9 @@ Boss* stage3_create_midboss(void) {
|
|||
Boss *scuttle = create_boss("Scuttle", "scuttle", VIEWPORT_W/2 - 200.0I);
|
||||
boss_add_attack(scuttle, AT_Move, "Introduction", 2, 0, stage3_mid_intro, NULL);
|
||||
boss_add_attack(scuttle, AT_Normal, "Lethal Bite", 30, 25000, stage3_mid_a0, NULL);
|
||||
boss_add_attack(scuttle, AT_Spellcard, "Venom Sign ~ Deadly Dance", 25, 25000, stage3_mid_a1, stage3_mid_spellbg);
|
||||
boss_add_attack_from_info(scuttle, stage3_spells+0, false);
|
||||
if(global.diff > D_Normal)
|
||||
boss_add_attack(scuttle, AT_Spellcard, "Venom Sign ~ Acid Rain", 20, 23000, stage3_mid_a2, stage3_mid_spellbg);
|
||||
boss_add_attack_from_info(scuttle, stage3_spells+1, false);
|
||||
boss_add_attack(scuttle, AT_Move, "Runaway", 2, 1, stage3_mid_outro, NULL);
|
||||
scuttle->zoomcolor = rgb(0.4, 0.5, 0.4);
|
||||
|
||||
|
@ -760,11 +776,11 @@ Boss* stage3_create_boss(void) {
|
|||
boss_add_attack(wriggle, AT_Move, "Introduction", 2, 0, stage3_boss_intro, NULL);
|
||||
|
||||
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea1, NULL);
|
||||
boss_add_attack(wriggle, AT_Spellcard, "Firefly Sign ~ Moonlight Rocket", 30, 20000, stage3_boss_a1, stage3_boss_spellbg);
|
||||
boss_add_attack_from_info(wriggle, stage3_spells+2, false);
|
||||
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea2, NULL);
|
||||
boss_add_attack(wriggle, AT_Spellcard, "Light Source ~ Wriggle Night Ignite", 25, 40000, stage3_boss_a2, stage3_boss_spellbg);
|
||||
boss_add_attack_from_info(wriggle, stage3_spells+3, false);
|
||||
boss_add_attack(wriggle, AT_Normal, "", 20, 15000, stage3_boss_prea3, NULL);
|
||||
boss_add_attack(wriggle, AT_Spellcard, "Bug Sign ~ Phosphaenus Hemipterus", 35, 30000, stage3_boss_a3, stage3_boss_spellbg);
|
||||
boss_add_attack_from_info(wriggle, stage3_spells+4, false);
|
||||
|
||||
start_attack(wriggle, wriggle->attacks);
|
||||
return wriggle;
|
||||
|
|
|
@ -232,5 +232,21 @@ void stage4_draw(void) {
|
|||
|
||||
void stage4_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage4_fog, NULL };
|
||||
stage_loop(stage_get(4), stage4_start, stage4_end, stage4_draw, stage4_events, shaderrules, 5550);
|
||||
stage_loop(stage4_start, stage4_end, stage4_draw, stage4_events, shaderrules, 5550);
|
||||
}
|
||||
|
||||
void stage4_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
skip_background_anim(&bgcontext, stage4_draw, 3200, &global.frames, NULL);
|
||||
global.boss = create_boss("Kurumi", "kurumi", BOSS_DEFAULT_SPAWN_POS);
|
||||
boss_add_attack_from_info(global.boss, global.stage->spell, true);
|
||||
start_attack(global.boss, global.boss->attacks);
|
||||
}
|
||||
}
|
||||
|
||||
void stage4_spellpractice_loop(void) {
|
||||
ShaderRule shaderrules[] = { stage4_fog, NULL };
|
||||
stage_loop(stage4_start, stage4_end, stage4_draw, stage4_spellpractice_events, shaderrules, 0);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
#ifndef STAGE4_H
|
||||
#define STAGE4_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage4_loop(void);
|
||||
void stage4_spellpractice_loop(void);
|
||||
|
||||
extern AttackInfo stage4_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,23 @@
|
|||
#include "enemy.h"
|
||||
#include "laser.h"
|
||||
|
||||
void kurumi_spell_bg(Boss*, int);
|
||||
void kurumi_slaveburst(Boss*, int);
|
||||
void kurumi_redspike(Boss*, int);
|
||||
void kurumi_aniwall(Boss*, int);
|
||||
void kurumi_blowwall(Boss*, int);
|
||||
void kurumi_danmaku(Boss*, int);
|
||||
|
||||
AttackInfo stage4_spells[] = {
|
||||
{AT_Spellcard, "Bloodless ~ Gate of Walachia", 25, 20000, kurumi_slaveburst, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Bloodless ~ Dry Fountain", 30, 30000, kurumi_redspike, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Bloodless ~ Red Spike", 30, 30000, kurumi_redspike, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Limit ~ Animate Wall", 30, 40000, kurumi_aniwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Summoning ~ Demon Wall", 30, 40000, kurumi_aniwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Power Sign ~ Blow the Walls", 30, 32000, kurumi_blowwall, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Fear Sign ~ Bloody Danmaku", 30, 32000, kurumi_danmaku, kurumi_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
};
|
||||
|
||||
Dialog *stage4_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/kurumi");
|
||||
|
||||
|
@ -229,7 +246,7 @@ void KurumiSlave(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
void kurumi_intro(Boss *b, int t) {
|
||||
GO_TO(b, VIEWPORT_W/2.0+200.0I, 0.01);
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.01);
|
||||
}
|
||||
|
||||
int kurumi_burstslave(Enemy *e, int t) {
|
||||
|
@ -363,8 +380,12 @@ void kurumi_outro(Boss *b, int time) {
|
|||
Boss *create_kurumi_mid(void) {
|
||||
Boss* b = create_boss("Kurumi", "kurumi", VIEWPORT_W/2-400.0I);
|
||||
boss_add_attack(b, AT_Move, "Introduction", 4, 0, kurumi_intro, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Bloodless ~ Gate of Walachia", 25, 20000, kurumi_slaveburst, kurumi_spell_bg);
|
||||
boss_add_attack(b, AT_Spellcard, global.diff < D_Hard ? "Bloodless ~ Dry Fountain" : "Bloodless ~ Red Spike", 30, 30000, kurumi_redspike, kurumi_spell_bg);
|
||||
boss_add_attack_from_info(b, stage4_spells+0, false);
|
||||
if(global.diff < D_Hard) {
|
||||
boss_add_attack_from_info(b, stage4_spells+1, false);
|
||||
} else {
|
||||
boss_add_attack_from_info(b, stage4_spells+2, false);
|
||||
}
|
||||
boss_add_attack(b, AT_Move, "Outro", 2, 1, kurumi_outro, NULL);
|
||||
start_attack(b, b->attacks);
|
||||
return b;
|
||||
|
@ -413,7 +434,7 @@ int stage4_supercard(Enemy *e, int t) {
|
|||
|
||||
void kurumi_boss_intro(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
GO_TO(b, VIEWPORT_W/2.0+200.0I, 0.01);
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.01);
|
||||
|
||||
AT(120)
|
||||
global.dialog = stage4_dialog();
|
||||
|
@ -704,11 +725,16 @@ Boss *create_kurumi(void) {
|
|||
Boss* b = create_boss("Kurumi", "kurumi", -400.0I);
|
||||
boss_add_attack(b, AT_Move, "Introduction", 4, 0, kurumi_boss_intro, NULL);
|
||||
boss_add_attack(b, AT_Normal, "Sin Breaker", 20, 20000, kurumi_sbreaker, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, global.diff < D_Hard ? "Limit ~ Animate Wall" : "Summoning ~ Demon Wall", 30, 40000, kurumi_aniwall, kurumi_spell_bg);
|
||||
if(global.diff < D_Hard) {
|
||||
boss_add_attack_from_info(b, stage4_spells+3, false);
|
||||
} else {
|
||||
boss_add_attack_from_info(b, stage4_spells+4, false);
|
||||
}
|
||||
boss_add_attack(b, AT_Normal, "Cold Breaker", 20, 20000, kurumi_breaker, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Power Sign ~ Blow the Walls", 30, 32000, kurumi_blowwall, kurumi_spell_bg);
|
||||
if(global.diff > D_Normal)
|
||||
boss_add_attack(b, AT_Spellcard, "Fear Sign ~ Bloody Danmaku", 30, 32000, kurumi_danmaku, kurumi_spell_bg);
|
||||
boss_add_attack_from_info(b, stage4_spells+5, false);
|
||||
if(global.diff > D_Normal) {
|
||||
boss_add_attack_from_info(b, stage4_spells+6, false);
|
||||
}
|
||||
start_attack(b, b->attacks);
|
||||
|
||||
return b;
|
||||
|
|
|
@ -130,5 +130,20 @@ void stage5_end(void) {
|
|||
}
|
||||
|
||||
void stage5_loop(void) {
|
||||
stage_loop(stage_get(5), stage5_start, stage5_end, stage5_draw, stage5_events, NULL, 5700);
|
||||
stage_loop(stage5_start, stage5_end, stage5_draw, stage5_events, NULL, 5700);
|
||||
}
|
||||
|
||||
void stage5_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
skip_background_anim(&bgcontext, stage5_draw, 5300, &global.timer, NULL);
|
||||
global.boss = create_boss("Nagae Iku", "iku", BOSS_DEFAULT_SPAWN_POS);
|
||||
boss_add_attack_from_info(global.boss, global.stage->spell, true);
|
||||
start_attack(global.boss, global.boss->attacks);
|
||||
}
|
||||
}
|
||||
|
||||
void stage5_spellpractice_loop(void) {
|
||||
stage_loop(stage5_start, stage5_end, stage5_draw, stage5_spellpractice_events, NULL, 5700);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
#ifndef STAGE5_H
|
||||
#define STAGE5_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage5_loop(void);
|
||||
void stage5_spellpractice_loop(void);
|
||||
|
||||
extern AttackInfo stage5_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,19 @@
|
|||
#include "stage5.h"
|
||||
#include <global.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);
|
||||
|
||||
AttackInfo stage5_spells[] = {
|
||||
{AT_Spellcard, "High Voltage ~ Atmospheric Discharge", 30, 30000, iku_atmospheric, iku_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Charge Sign ~ Artificial Lightning", 30, 35000, iku_lightning, iku_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Spark Sign ~ Natural Cathode", 30, 35000, iku_cathode, iku_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Current Sign ~ Induction", 30, 35000, iku_induction, iku_spell_bg, BOSS_DEFAULT_GO_POS},
|
||||
};
|
||||
|
||||
Dialog *stage5_post_mid_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", NULL);
|
||||
|
||||
|
@ -377,7 +390,7 @@ void iku_lightning(Boss *b, int time) {
|
|||
}
|
||||
|
||||
if(time < 0) {
|
||||
GO_TO(b, VIEWPORT_W/2.0+200.0I, 0.03);
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.03);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -485,12 +498,12 @@ Boss *create_iku(void) {
|
|||
|
||||
boss_add_attack(b, AT_Move, "Introduction", 3, 0, iku_intro, NULL);
|
||||
boss_add_attack(b, AT_Normal, "Bolts1", 20, 20000, iku_bolts, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "High Voltage ~ Atmospheric Discharge", 30, 30000, iku_atmospheric, iku_spell_bg);
|
||||
boss_add_attack_from_info(b, stage5_spells+0, false);
|
||||
boss_add_attack(b, AT_Normal, "Bolts2", 25, 20000, iku_bolts2, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Charge Sign ~ Artificial Lightning", 30, 35000, iku_lightning, iku_spell_bg);
|
||||
boss_add_attack_from_info(b, stage5_spells+1, false);
|
||||
boss_add_attack(b, AT_Normal, "Bolts3", 20, 20000, iku_bolts3, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Spark Sign ~ Natural Cathode", 30, 35000, iku_cathode, iku_spell_bg);
|
||||
boss_add_attack(b, AT_Spellcard, "Current Sign ~ Induction", 30, 35000, iku_induction, iku_spell_bg);
|
||||
boss_add_attack_from_info(b, stage5_spells+2, false);
|
||||
boss_add_attack_from_info(b, stage5_spells+3, false);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
|
|
@ -176,5 +176,61 @@ void stage6_end(void) {
|
|||
|
||||
void stage6_loop(void) {
|
||||
// ShaderRule shaderrules[] = { stage6_bloom, NULL };
|
||||
stage_loop(stage_get(6), stage6_start, stage6_end, stage6_draw, stage6_events, NULL, 3900);
|
||||
stage_loop(stage6_start, stage6_end, stage6_draw, stage6_events, NULL, 3900);
|
||||
}
|
||||
|
||||
void elly_intro(Boss*, int);
|
||||
void elly_unbound(Boss*, int);
|
||||
|
||||
void stage6_spellpractice_events(void) {
|
||||
TIMER(&global.timer);
|
||||
|
||||
AT(0) {
|
||||
skip_background_anim(&bgcontext, stage6_draw, 3800, &global.timer, &global.frames);
|
||||
global.boss = create_boss("Elly", "elly", BOSS_DEFAULT_SPAWN_POS);
|
||||
|
||||
// Here be dragons
|
||||
|
||||
ptrdiff_t spellnum = global.stage->spell - stage6_spells;
|
||||
char go = true;
|
||||
|
||||
switch(spellnum) {
|
||||
case 0: // Newton Sign ~ 2.5 Laws of Movement
|
||||
// Scythe required - this creates it
|
||||
boss_add_attack(global.boss, AT_Move, "Catch the Scythe", 2, 0, elly_intro, NULL);
|
||||
go = false;
|
||||
break;
|
||||
|
||||
case 1: // Maxwell Sign ~ Wave Theory
|
||||
// Works fine on its own
|
||||
break;
|
||||
|
||||
case 2: // Eigenstate ~ Many-World Interpretation
|
||||
case 3: // Ricci Sign ~ Space Time Curvature
|
||||
case 4: // LHC ~ Higgs Boson Uncovered
|
||||
// Baryon required - this creates it
|
||||
boss_add_attack(global.boss, AT_Move, "Unbound", 3, 0, elly_unbound, NULL);
|
||||
go = false;
|
||||
break;
|
||||
|
||||
case 5: // Tower of Truth ~ Theory of Everything
|
||||
// Works fine on its own
|
||||
// Just needs a little extra to make us fall from the tower
|
||||
start_fall_over();
|
||||
skip_background_anim(&bgcontext, stage6_draw, 300, &global.timer, &global.frames);
|
||||
break;
|
||||
}
|
||||
|
||||
boss_add_attack_from_info(global.boss, global.stage->spell, go);
|
||||
start_attack(global.boss, global.boss->attacks);
|
||||
}
|
||||
|
||||
if(!global.boss) {
|
||||
killall(global.enemies);
|
||||
}
|
||||
}
|
||||
|
||||
void stage6_spellpractice_loop(void) {
|
||||
// ShaderRule shaderrules[] = { stage6_bloom, NULL };
|
||||
stage_loop(stage6_start, stage6_end, stage6_draw, stage6_spellpractice_events, NULL, 3900);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,12 @@
|
|||
#ifndef STAGE6_H
|
||||
#define STAGE6_H
|
||||
|
||||
#include "boss.h"
|
||||
|
||||
void stage6_loop(void);
|
||||
void stage6_spellpractice_loop(void);
|
||||
void start_fall_over(void);
|
||||
|
||||
extern AttackInfo stage6_spells[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,24 @@
|
|||
#include "stage6.h"
|
||||
#include <global.h>
|
||||
|
||||
void elly_spellbg_classic(Boss*, int);
|
||||
void elly_spellbg_modern(Boss*, int);
|
||||
void elly_newton(Boss*, int);
|
||||
void elly_maxwell(Boss*, int);
|
||||
void elly_eigenstate(Boss*, int);
|
||||
void elly_ricci(Boss*, int);
|
||||
void elly_lhc(Boss*, int);
|
||||
void elly_theory(Boss*, int);
|
||||
|
||||
AttackInfo stage6_spells[] = {
|
||||
{AT_Spellcard, "Newton Sign ~ 2.5 Laws of Movement", 60, 40000, elly_newton, elly_spellbg_classic, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Maxwell Sign ~ Wave Theory", 25, 22000, elly_maxwell, elly_spellbg_classic, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Eigenstate ~ Many-World Interpretation", 60, 30000, elly_eigenstate, elly_spellbg_modern, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "Ricci Sign ~ Space Time Curvature", 50, 40000, elly_ricci, elly_spellbg_modern, BOSS_DEFAULT_GO_POS},
|
||||
{AT_Spellcard, "LHC ~ Higgs Boson Uncovered", 60, 50000, elly_lhc, elly_spellbg_modern, BOSS_DEFAULT_GO_POS},
|
||||
{AT_SurvivalSpell, "Tower of Truth ~ Theory of Everything", 70, 40000, elly_theory, elly_spellbg_modern, BOSS_DEFAULT_GO_POS},
|
||||
};
|
||||
|
||||
Dialog *stage6_dialog(void) {
|
||||
Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "dialog/elly");
|
||||
|
||||
|
@ -181,7 +199,18 @@ int scythe_intro(Enemy *e, int t) {
|
|||
|
||||
void elly_intro(Boss *b, int t) {
|
||||
TIMER(&t);
|
||||
GO_TO(b, VIEWPORT_W/2+200.0I, 0.01);
|
||||
|
||||
if(global.stage->type == STAGE_SPELL) {
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.1);
|
||||
|
||||
AT(0) {
|
||||
create_enemy3c(VIEWPORT_W+200.0I, ENEMY_IMMUNE, Scythe, scythe_intro, 0, 1+0.2I, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.01);
|
||||
|
||||
AT(200) {
|
||||
create_enemy3c(VIEWPORT_W+200+200.0I, ENEMY_IMMUNE, Scythe, scythe_intro, 0, 1+0.2I, 1);
|
||||
|
@ -224,7 +253,7 @@ int scythe_reset(Enemy *e, int t) {
|
|||
if(t == 1)
|
||||
e->args[1] = fmod(creal(e->args[1]), 2*M_PI) + I*cimag(e->args[1]);
|
||||
|
||||
GO_TO(e, VIEWPORT_W/2.0+200.0I, 0.02);
|
||||
GO_TO(e, BOSS_DEFAULT_GO_POS, 0.02);
|
||||
e->args[2] = max(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]);
|
||||
|
@ -478,6 +507,11 @@ int scythe_explode(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
void elly_unbound(Boss *b, int t) {
|
||||
if(global.stage->type == STAGE_SPELL) {
|
||||
t += 100;
|
||||
GO_TO(b, BOSS_DEFAULT_GO_POS, 0.1)
|
||||
}
|
||||
|
||||
TIMER(&t);
|
||||
|
||||
AT(0) {
|
||||
|
@ -916,17 +950,17 @@ Boss *create_elly(void) {
|
|||
|
||||
boss_add_attack(b, AT_Move, "Catch the Scythe", 6, 0, elly_intro, NULL);
|
||||
boss_add_attack(b, AT_Normal, "Frequency", 30, 26000, elly_frequency, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Newton Sign ~ 2.5 Laws of Movement", 60, 40000, elly_newton, elly_spellbg_classic);
|
||||
boss_add_attack_from_info(b, stage6_spells+0, false);
|
||||
boss_add_attack(b, AT_Normal, "Frequency2", 40, 23000, elly_frequency2, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Maxwell Sign ~ Wave Theory", 25, 22000, elly_maxwell, elly_spellbg_classic);
|
||||
boss_add_attack_from_info(b, stage6_spells+1, false);
|
||||
boss_add_attack(b, AT_Move, "Unbound", 6, 10, elly_unbound, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Eigenstate ~ Many-World Interpretation", 60, 30000, elly_eigenstate, elly_spellbg_modern);
|
||||
boss_add_attack_from_info(b, stage6_spells+2, false);
|
||||
boss_add_attack(b, AT_Normal, "Baryon", 40, 23000, elly_baryonattack, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "Ricci Sign ~ Space Time Curvature", 50, 40000, elly_ricci, elly_spellbg_modern);
|
||||
boss_add_attack_from_info(b, stage6_spells+3, false);
|
||||
boss_add_attack(b, AT_Normal, "Baryon", 25, 23000, elly_baryonattack2, NULL);
|
||||
boss_add_attack(b, AT_Spellcard, "LHC ~ Higgs Boson Uncovered", 60, 50000, elly_lhc, elly_spellbg_modern);
|
||||
boss_add_attack_from_info(b, stage6_spells+4, false);
|
||||
boss_add_attack(b, AT_Move, "Explode", 6, 10, elly_baryon_explode, NULL);
|
||||
boss_add_attack(b, AT_SurvivalSpell, "Tower of Truth ~ Theory of Everything", 70, 40000, elly_theory, elly_spellbg_modern);
|
||||
boss_add_attack_from_info(b, stage6_spells+5, false);
|
||||
start_attack(b, b->attacks);
|
||||
|
||||
return b;
|
||||
|
|
|
@ -43,6 +43,10 @@ void draw_stage3d(Stage3D *s, float maxrange) {
|
|||
for(i = 0; i < 3;i++)
|
||||
s->cx[i] += s->cv[i];
|
||||
|
||||
if(s->nodraw) {
|
||||
return;
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
if(s->crot[0])
|
||||
|
@ -138,3 +142,29 @@ Vector **single3dpos(Vector q, float maxrange, Vector p) {
|
|||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
void skip_background_anim(Stage3D *s3d, void (*drawfunc)(void), int frames, int *timer, int *timer2) {
|
||||
// two timers because stage 6 is so fucking special
|
||||
// second is optional
|
||||
|
||||
if(s3d) {
|
||||
s3d->nodraw = true;
|
||||
}
|
||||
|
||||
int targetframes = *timer + frames;
|
||||
|
||||
while(++(*timer) < targetframes) {
|
||||
if(timer2) {
|
||||
++(*timer2);
|
||||
}
|
||||
drawfunc();
|
||||
}
|
||||
|
||||
if(timer2) {
|
||||
++(*timer2);
|
||||
}
|
||||
|
||||
if(s3d) {
|
||||
s3d->nodraw = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ struct Stage3D {
|
|||
Vector crot;
|
||||
|
||||
float projangle;
|
||||
|
||||
// hack to quickly skip through stage animations up to a specific frame
|
||||
char nodraw;
|
||||
};
|
||||
|
||||
void init_stage3d(Stage3D *s);
|
||||
|
@ -47,4 +50,7 @@ void free_stage3d(Stage3D *s);
|
|||
Vector **linear3dpos(Vector q, float maxrange, Vector p, Vector r);
|
||||
|
||||
Vector **single3dpos(Vector q, float maxrange, Vector p);
|
||||
|
||||
void skip_background_anim(Stage3D *s3d, void (*drawfunc)(void), int frames, int *timer, int *timer2);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue