Separate StageInfo-related APIs from game-stage code (#227)
This commit is contained in:
parent
f7763fe6f4
commit
00e4837827
31 changed files with 406 additions and 306 deletions
|
@ -16,6 +16,7 @@
|
|||
#include "entity.h"
|
||||
#include "util/glm.h"
|
||||
#include "portrait.h"
|
||||
#include "stages/stage5.h" // for unlockable bonus BGM
|
||||
|
||||
static void ent_draw_boss(EntityInterface *ent);
|
||||
static DamageResult ent_damage_boss(EntityInterface *ent, const DamageInfo *dmg);
|
||||
|
@ -110,7 +111,7 @@ static inline bool healthbar_style_is_radial(void) {
|
|||
return config_get_int(CONFIG_HEALTHBAR_STYLE) > 0;
|
||||
}
|
||||
|
||||
static const Color* boss_healthbar_color(AttackType atype) {
|
||||
static const Color *boss_healthbar_color(AttackType atype) {
|
||||
static const Color colors[] = {
|
||||
[AT_Normal] = { 0.50, 0.50, 0.60, 1.00 },
|
||||
[AT_Move] = { 1.00, 1.00, 1.00, 1.00 },
|
||||
|
@ -124,11 +125,11 @@ static const Color* boss_healthbar_color(AttackType atype) {
|
|||
return colors + atype;
|
||||
}
|
||||
|
||||
static StageProgress* get_spellstage_progress(Attack *a, StageInfo **out_stginfo, bool write) {
|
||||
static StageProgress *get_spellstage_progress(Attack *a, StageInfo **out_stginfo, bool write) {
|
||||
if(!write || (global.replaymode == REPLAY_RECORD && global.stage->type == STAGE_STORY)) {
|
||||
StageInfo *i = stage_get_by_spellcard(a->info, global.diff);
|
||||
StageInfo *i = stageinfo_get_by_spellcard(a->info, global.diff);
|
||||
if(i) {
|
||||
StageProgress *p = stage_get_progress_from_info(i, global.diff, write);
|
||||
StageProgress *p = stageinfo_get_progress(i, global.diff, write);
|
||||
|
||||
if(out_stginfo) {
|
||||
*out_stginfo = i;
|
||||
|
|
|
@ -210,7 +210,7 @@ int cli_args(int argc, char **argv, CLIAction *a) {
|
|||
case CLI_PlayReplay:
|
||||
case CLI_VerifyReplay:
|
||||
case CLI_SelectStage:
|
||||
if(stage_get(stageid) == NULL) {
|
||||
if(stageinfo_get_by_id(stageid) == NULL) {
|
||||
log_fatal("Invalid stage id: %X", stageid);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "log.h"
|
||||
#include "framerate.h"
|
||||
#include "renderer/api.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
enum {
|
||||
// defaults
|
||||
|
|
14
src/main.c
14
src/main.c
|
@ -14,7 +14,7 @@
|
|||
#include "global.h"
|
||||
#include "video.h"
|
||||
#include "audio/audio.h"
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
#include "menu/mainmenu.h"
|
||||
#include "menu/savereplay.h"
|
||||
#include "gamepad.h"
|
||||
|
@ -45,7 +45,7 @@ static void taisei_shutdown(void) {
|
|||
audio_shutdown();
|
||||
video_shutdown();
|
||||
gamepad_shutdown();
|
||||
stage_free_array();
|
||||
stageinfo_shutdown();
|
||||
config_shutdown();
|
||||
vfs_shutdown();
|
||||
events_shutdown();
|
||||
|
@ -213,7 +213,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
setlocale(LC_ALL, "C");
|
||||
init_log();
|
||||
stage_init_array(); // cli_args depends on this
|
||||
stageinfo_init(); // cli_args depends on this
|
||||
|
||||
// commandline arguments should be parsed as early as possible
|
||||
cli_args(argc, argv, &ctx->cli); // stage_init_array goes first!
|
||||
|
@ -223,9 +223,11 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if(ctx->cli.type == CLI_DumpStages) {
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
tsfprintf(stdout, "%X %s: %s\n", stg->id, stg->title, stg->subtitle);
|
||||
});
|
||||
}
|
||||
|
||||
main_quit(ctx, 0);
|
||||
}
|
||||
|
@ -373,7 +375,7 @@ static void main_singlestg(MainContext *mctx) {
|
|||
CLIAction *a = &mctx->cli;
|
||||
log_info("Entering stage skip mode: Stage %X", a->stageid);
|
||||
|
||||
StageInfo* stg = stage_get(a->stageid);
|
||||
StageInfo *stg = stageinfo_get_by_id(a->stageid);
|
||||
assert(stg); // properly checked before this
|
||||
|
||||
SingleStageContext *ctx = calloc(1, sizeof(*ctx));
|
||||
|
|
|
@ -39,7 +39,7 @@ static void start_game_internal(MenuData *menu, StageInfo *info, bool difficulty
|
|||
|
||||
if(info == NULL) {
|
||||
global.is_practice_mode = false;
|
||||
ctx->current_stage = ctx->restart_stage = dynarray_get_ptr(&stages, 0);
|
||||
ctx->current_stage = ctx->restart_stage = stageinfo_get_by_id(1);
|
||||
} else {
|
||||
global.is_practice_mode = (info->type != STAGE_EXTRA);
|
||||
ctx->current_stage = info;
|
||||
|
|
|
@ -32,9 +32,12 @@ void main_menu_update_practice_menus(void) {
|
|||
spell_practice_entry->action = NULL;
|
||||
stage_practice_entry->action = NULL;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
|
||||
if(stg->type == STAGE_SPELL) {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, D_Any, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, D_Any, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
spell_practice_entry->action = menu_action_enter_spellpractice;
|
||||
|
@ -44,7 +47,7 @@ void main_menu_update_practice_menus(void) {
|
|||
}
|
||||
} else if(stg->type == STAGE_STORY) {
|
||||
for(Difficulty d = D_Easy; d <= D_Lunatic; ++d) {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, d, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, d, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
stage_practice_entry->action = menu_action_enter_stagepractice;
|
||||
|
@ -54,7 +57,7 @@ void main_menu_update_practice_menus(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void begin_main_menu(MenuData *m) {
|
||||
|
|
|
@ -84,7 +84,7 @@ static void start_replay(MenuData *menu, void *arg) {
|
|||
ReplayStage *stg = rpy->stages + stagenum;
|
||||
char buf[64];
|
||||
|
||||
if(!stage_get(stg->stage)) {
|
||||
if(!stageinfo_get_by_id(stg->stage)) {
|
||||
replay_destroy_events(rpy);
|
||||
snprintf(buf, sizeof(buf), "Can't replay this stage: unknown stage ID %X", stg->stage);
|
||||
replayview_set_submenu(menu, replayview_sub_messagebox(menu, buf));
|
||||
|
@ -119,7 +119,7 @@ static MenuData* replayview_sub_stageselect(MenuData *parent, ReplayviewItemCont
|
|||
m->context = parent->context;
|
||||
|
||||
for(int i = 0; i < rpy->numstages; ++i) {
|
||||
add_menu_entry(m, stage_get(rpy->stages[i].stage)->title, start_replay, ictx)/*->transition = TransFadeBlack*/;
|
||||
add_menu_entry(m, stageinfo_get_by_id(rpy->stages[i].stage)->title, start_replay, ictx)/*->transition = TransFadeBlack*/;
|
||||
}
|
||||
|
||||
return m;
|
||||
|
@ -276,7 +276,7 @@ static void replayview_drawitem(MenuEntry *e, int item, int cnt) {
|
|||
case 4:
|
||||
a = ALIGN_LEFT;
|
||||
if(rpy->numstages == 1) {
|
||||
StageInfo *stg = stage_get(rpy->stages[0].stage);
|
||||
StageInfo *stg = stageinfo_get_by_id(rpy->stages[0].stage);
|
||||
|
||||
if(stg) {
|
||||
snprintf(tmp, sizeof(tmp), "%s", stg->title);
|
||||
|
|
|
@ -31,7 +31,10 @@ MenuData* create_spell_menu(void) {
|
|||
m->flags = MF_Abortable;
|
||||
m->transition = TransFadeBlack;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
|
||||
if(stg->type != STAGE_SPELL) {
|
||||
continue;
|
||||
}
|
||||
|
@ -40,7 +43,8 @@ MenuData* create_spell_menu(void) {
|
|||
add_menu_separator(m);
|
||||
}
|
||||
|
||||
StageProgress *p = stage_get_progress_from_info(stg, D_Any, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, D_Any, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
snprintf(title, sizeof(title), "%s: %s", stg->title, stg->subtitle);
|
||||
add_menu_entry(m, title, start_game, stg);
|
||||
|
@ -50,7 +54,7 @@ MenuData* create_spell_menu(void) {
|
|||
}
|
||||
|
||||
lastdiff = stg->difficulty;
|
||||
});
|
||||
}
|
||||
|
||||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_action_close, NULL);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "options.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
static void draw_stgpract_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
|
@ -30,12 +31,15 @@ MenuData* create_stgpract_menu(Difficulty diff) {
|
|||
m->flags = MF_Abortable;
|
||||
m->transition = TransFadeBlack;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
|
||||
if(stg->type != STAGE_STORY) {
|
||||
break;
|
||||
}
|
||||
|
||||
StageProgress *p = stage_get_progress_from_info(stg, diff, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, diff, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
snprintf(title, sizeof(title), "%s: %s", stg->title, stg->subtitle);
|
||||
|
@ -44,7 +48,7 @@ MenuData* create_stgpract_menu(Difficulty diff) {
|
|||
snprintf(title, sizeof(title), "%s: ???????", stg->title);
|
||||
add_menu_entry(m, title, NULL, NULL);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_action_close, NULL);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "stageselect.h"
|
||||
#include "common.h"
|
||||
#include "video.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
static void draw_stage_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
|
@ -33,7 +34,9 @@ MenuData* create_stage_menu(void) {
|
|||
m->flags = MF_Abortable;
|
||||
m->transition = TransFadeBlack;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
Difficulty diff = stg->difficulty;
|
||||
|
||||
if(diff < lastdiff || (diff == D_Extra && lastdiff != D_Extra) || (diff && !lastdiff)) {
|
||||
|
@ -44,7 +47,7 @@ MenuData* create_stage_menu(void) {
|
|||
add_menu_entry(m, title, start_game, stg);
|
||||
|
||||
lastdiff = diff;
|
||||
});
|
||||
}
|
||||
|
||||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_action_close, NULL);
|
||||
|
|
|
@ -91,6 +91,7 @@ taisei_src = files(
|
|||
'replay.c',
|
||||
'stage.c',
|
||||
'stagedraw.c',
|
||||
'stageinfo.c',
|
||||
'stageobjects.c',
|
||||
'stagetext.c',
|
||||
'stageutils.c',
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <zlib.h>
|
||||
|
||||
#include "progress.h"
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
#include "version.h"
|
||||
|
||||
/*
|
||||
|
@ -165,7 +165,7 @@ static void progress_read(SDL_RWops *file) {
|
|||
switch(cmd) {
|
||||
case PCMD_UNLOCK_STAGES:
|
||||
while(cur < cmdsize) {
|
||||
StageProgress *p = stage_get_progress(SDL_ReadLE16(vfile), D_Any, true);
|
||||
StageProgress *p = stageinfo_get_progress_by_id(SDL_ReadLE16(vfile), D_Any, true);
|
||||
if(p) {
|
||||
p->unlocked = true;
|
||||
}
|
||||
|
@ -177,11 +177,11 @@ static void progress_read(SDL_RWops *file) {
|
|||
while(cur < cmdsize) {
|
||||
uint16_t stg = SDL_ReadLE16(vfile);
|
||||
uint8_t dflags = SDL_ReadU8(vfile);
|
||||
StageInfo *info = stage_get(stg);
|
||||
StageInfo *info = stageinfo_get_by_id(stg);
|
||||
|
||||
for(uint diff = D_Easy; diff <= D_Lunatic; ++diff) {
|
||||
if(dflags & (uint)pow(2, diff - D_Easy)) {
|
||||
StageProgress *p = stage_get_progress_from_info(info, diff, true);
|
||||
StageProgress *p = stageinfo_get_progress(info, diff, true);
|
||||
if(p) {
|
||||
p->unlocked = true;
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ static void progress_read(SDL_RWops *file) {
|
|||
while(cur < cmdsize) {
|
||||
uint16_t stg = SDL_ReadLE16(vfile); cur += sizeof(uint16_t);
|
||||
Difficulty diff = SDL_ReadU8(vfile); cur += sizeof(uint8_t);
|
||||
StageProgress *p = stage_get_progress(stg, diff, true);
|
||||
StageProgress *p = stageinfo_get_progress_by_id(stg, diff, true);
|
||||
|
||||
// assert(p != NULL);
|
||||
|
||||
|
@ -315,12 +315,15 @@ typedef struct cmd_writer_t {
|
|||
static void progress_prepare_cmd_unlock_stages(size_t *bufsize, void **arg) {
|
||||
int num_unlocked = 0;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, D_Any, false);
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
StageProgress *p = stageinfo_get_progress(stg, D_Any, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
++num_unlocked;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(num_unlocked) {
|
||||
*bufsize += CMD_HEADER_SIZE;
|
||||
|
@ -340,12 +343,15 @@ static void progress_write_cmd_unlock_stages(SDL_RWops *vfile, void **arg) {
|
|||
SDL_WriteU8(vfile, PCMD_UNLOCK_STAGES);
|
||||
SDL_WriteLE16(vfile, num_unlocked * 2);
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, D_Any, false);
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
StageProgress *p = stageinfo_get_progress(stg, D_Any, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
SDL_WriteLE16(vfile, stg->id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -355,7 +361,10 @@ static void progress_write_cmd_unlock_stages(SDL_RWops *vfile, void **arg) {
|
|||
static void progress_prepare_cmd_unlock_stages_with_difficulties(size_t *bufsize, void **arg) {
|
||||
int num_unlocked = 0;
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
|
||||
if(stg->difficulty) {
|
||||
continue;
|
||||
}
|
||||
|
@ -363,7 +372,8 @@ static void progress_prepare_cmd_unlock_stages_with_difficulties(size_t *bufsize
|
|||
bool unlocked = false;
|
||||
|
||||
for(Difficulty diff = D_Easy; diff <= D_Lunatic; ++diff) {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, diff, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, diff, false);
|
||||
|
||||
if(p && p->unlocked) {
|
||||
unlocked = true;
|
||||
}
|
||||
|
@ -372,7 +382,7 @@ static void progress_prepare_cmd_unlock_stages_with_difficulties(size_t *bufsize
|
|||
if(unlocked) {
|
||||
++num_unlocked;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(num_unlocked) {
|
||||
*bufsize += CMD_HEADER_SIZE;
|
||||
|
@ -392,7 +402,10 @@ static void progress_write_cmd_unlock_stages_with_difficulties(SDL_RWops *vfile,
|
|||
SDL_WriteU8(vfile, PCMD_UNLOCK_STAGES_WITH_DIFFICULTY);
|
||||
SDL_WriteLE16(vfile, num_unlocked * 3);
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
|
||||
if(stg->difficulty) {
|
||||
continue;
|
||||
}
|
||||
|
@ -400,7 +413,7 @@ static void progress_write_cmd_unlock_stages_with_difficulties(SDL_RWops *vfile,
|
|||
uint8_t dflags = 0;
|
||||
|
||||
for(Difficulty diff = D_Easy; diff <= D_Lunatic; ++diff) {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, diff, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, diff, false);
|
||||
if(p && p->unlocked) {
|
||||
dflags |= (uint)pow(2, diff - D_Easy);
|
||||
}
|
||||
|
@ -410,7 +423,7 @@ static void progress_write_cmd_unlock_stages_with_difficulties(SDL_RWops *vfile,
|
|||
SDL_WriteLE16(vfile, stg->id);
|
||||
SDL_WriteU8(vfile, dflags);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -448,7 +461,9 @@ static void progress_prepare_cmd_stage_playinfo(size_t *bufsize, void **arg) {
|
|||
struct cmd_stage_playinfo_data *data = malloc(sizeof(struct cmd_stage_playinfo_data));
|
||||
memset(data, 0, sizeof(struct cmd_stage_playinfo_data));
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
int n = stageinfo_get_num_stages();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
StageInfo *stg = stageinfo_get_by_index(i);
|
||||
Difficulty d_first, d_last;
|
||||
|
||||
if(stg->difficulty == D_Any) {
|
||||
|
@ -459,7 +474,7 @@ static void progress_prepare_cmd_stage_playinfo(size_t *bufsize, void **arg) {
|
|||
}
|
||||
|
||||
for(Difficulty d = d_first; d <= d_last; ++d) {
|
||||
StageProgress *p = stage_get_progress_from_info(stg, d, false);
|
||||
StageProgress *p = stageinfo_get_progress(stg, d, false);
|
||||
|
||||
if(p && (p->num_played || p->num_cleared)) {
|
||||
struct cmd_stage_playinfo_data_elem *e = malloc(sizeof(struct cmd_stage_playinfo_data_elem));
|
||||
|
@ -472,7 +487,7 @@ static void progress_prepare_cmd_stage_playinfo(size_t *bufsize, void **arg) {
|
|||
(void)list_push(&data->elems, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
*arg = data;
|
||||
|
||||
|
|
10
src/replay.c
10
src/replay.c
|
@ -868,13 +868,13 @@ void replay_play(Replay *rpy, int firstidx, CallChain next) {
|
|||
static void replay_do_play(CallChainResult ccr) {
|
||||
ReplayContext *ctx = ccr.ctx;
|
||||
ReplayStage *rstg = NULL;
|
||||
StageInfo *gstg = NULL;
|
||||
StageInfo *stginfo = NULL;
|
||||
|
||||
while(ctx->stage_idx < global.replay.numstages) {
|
||||
rstg = global.replay_stage = global.replay.stages + ctx->stage_idx++;
|
||||
gstg = stage_get(rstg->stage);
|
||||
stginfo = stageinfo_get_by_id(rstg->stage);
|
||||
|
||||
if(!gstg) {
|
||||
if(!stginfo) {
|
||||
log_warn("Invalid stage %X in replay at %i skipped.", rstg->stage, ctx->stage_idx);
|
||||
continue;
|
||||
}
|
||||
|
@ -882,11 +882,11 @@ static void replay_do_play(CallChainResult ccr) {
|
|||
break;
|
||||
}
|
||||
|
||||
if(gstg == NULL) {
|
||||
if(stginfo == NULL) {
|
||||
replay_do_cleanup(ccr);
|
||||
} else {
|
||||
global.plr.mode = plrmode_find(rstg->plr_char, rstg->plr_shot);
|
||||
stage_enter(gstg, CALLCHAIN(replay_do_post_play, ctx));
|
||||
stage_enter(stginfo, CALLCHAIN(replay_do_post_play, ctx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
188
src/stage.c
188
src/stage.c
|
@ -25,185 +25,7 @@
|
|||
#include "stageobjects.h"
|
||||
#include "eventloop/eventloop.h"
|
||||
#include "common_tasks.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPSTEST
|
||||
#include "stages/dpstest.h"
|
||||
#endif
|
||||
|
||||
StageInfoArray stages = { 0 };
|
||||
|
||||
static void add_stage(uint16_t id, StageProcs *procs, StageType type, const char *title, const char *subtitle, AttackInfo *spell, Difficulty diff) {
|
||||
StageInfo *stg = dynarray_append(&stages);
|
||||
|
||||
stg->id = id;
|
||||
stg->procs = procs;
|
||||
stg->type = type;
|
||||
stralloc(&stg->title, title);
|
||||
stralloc(&stg->subtitle, subtitle);
|
||||
stg->spell = spell;
|
||||
stg->difficulty = diff;
|
||||
}
|
||||
|
||||
static void add_spellpractice_stage(StageInfo *s, AttackInfo *a, int *spellnum, uint16_t spellbits, Difficulty diff) {
|
||||
uint16_t id = spellbits | a->idmap[diff - D_Easy] | (s->id << 8);
|
||||
|
||||
char *title = strfmt("Spell %d", ++(*spellnum));
|
||||
char *subtitle = strjoin(a->name, " ~ ", difficulty_name(diff), NULL);
|
||||
|
||||
add_stage(id, s->procs->spellpractice_procs, STAGE_SPELL, title, subtitle, a, diff);
|
||||
|
||||
free(title);
|
||||
free(subtitle);
|
||||
}
|
||||
|
||||
static void add_spellpractice_stages(int *spellnum, bool (*filter)(AttackInfo*), uint16_t spellbits) {
|
||||
for(int i = 0 ;; ++i) {
|
||||
StageInfo *s = dynarray_get_ptr(&stages, i);
|
||||
|
||||
if(s->type == STAGE_SPELL || !s->spell) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(AttackInfo *a = s->spell; a->name; ++a) {
|
||||
if(!filter(a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(Difficulty diff = D_Easy; diff < D_Easy + NUM_SELECTABLE_DIFFICULTIES; ++diff) {
|
||||
if(a->idmap[diff - D_Easy] >= 0) {
|
||||
add_spellpractice_stage(s, a, spellnum, spellbits, diff);
|
||||
|
||||
// stages may have gotten realloc'd, so we must update the pointer
|
||||
s = dynarray_get_ptr(&stages, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool spellfilter_normal(AttackInfo *spell) {
|
||||
return spell->type != AT_ExtraSpell;
|
||||
}
|
||||
|
||||
static bool spellfilter_extra(AttackInfo *spell) {
|
||||
return spell->type == AT_ExtraSpell;
|
||||
}
|
||||
|
||||
#include "stages/corotest.h"
|
||||
|
||||
void stage_init_array(void) {
|
||||
int spellnum = 0;
|
||||
|
||||
// id procs type title subtitle spells diff
|
||||
add_stage(1, &stage1_procs, STAGE_STORY, "Stage 1", "Misty Lake", (AttackInfo*)&stage1_spells, D_Any);
|
||||
add_stage(2, &stage2_procs, STAGE_STORY, "Stage 2", "Walk Along the Border", (AttackInfo*)&stage2_spells, D_Any);
|
||||
add_stage(3, &stage3_procs, STAGE_STORY, "Stage 3", "Through the Tunnel of Light", (AttackInfo*)&stage3_spells, D_Any);
|
||||
add_stage(4, &stage4_procs, STAGE_STORY, "Stage 4", "Forgotten Mansion", (AttackInfo*)&stage4_spells, D_Any);
|
||||
add_stage(5, &stage5_procs, STAGE_STORY, "Stage 5", "Climbing the Tower of Babel", (AttackInfo*)&stage5_spells, D_Any);
|
||||
add_stage(6, &stage6_procs, STAGE_STORY, "Stage 6", "Roof of the World", (AttackInfo*)&stage6_spells, D_Any);
|
||||
|
||||
#ifdef DPSTEST
|
||||
add_stage(0x40|0, &stage_dpstest_single_procs, STAGE_SPECIAL, "DPS Test", "Single target", NULL, D_Normal);
|
||||
add_stage(0x40|1, &stage_dpstest_multi_procs, STAGE_SPECIAL, "DPS Test", "Multiple targets", NULL, D_Normal);
|
||||
add_stage(0x40|2, &stage_dpstest_boss_procs, STAGE_SPECIAL, "DPS Test", "Boss", NULL, D_Normal);
|
||||
#endif
|
||||
|
||||
// generate spellpractice stages
|
||||
add_spellpractice_stages(&spellnum, spellfilter_normal, STAGE_SPELL_BIT);
|
||||
add_spellpractice_stages(&spellnum, spellfilter_extra, STAGE_SPELL_BIT | STAGE_EXTRASPELL_BIT);
|
||||
|
||||
#ifdef SPELL_BENCHMARK
|
||||
add_spellpractice_stage(dynarray_get_ptr(&stages, 0), &stage1_spell_benchmark, &spellnum, STAGE_SPELL_BIT, D_Extra);
|
||||
#endif
|
||||
|
||||
add_stage(0xC0, &corotest_procs, STAGE_SPECIAL, "Coroutines!", "wow such concurrency very async", NULL, D_Any);
|
||||
add_stage(0xC1, &extra_procs, STAGE_SPECIAL, "Extra Stage", "Descent into Madness", NULL, D_Extra);
|
||||
|
||||
dynarray_compact(&stages);
|
||||
|
||||
#ifdef DEBUG
|
||||
dynarray_foreach(&stages, int i, StageInfo *stg, {
|
||||
if(stg->type == STAGE_SPELL && !(stg->id & STAGE_SPELL_BIT)) {
|
||||
log_fatal("Spell stage has an ID without the spell bit set: 0x%04x", stg->id);
|
||||
}
|
||||
|
||||
dynarray_foreach(&stages, int j, StageInfo *stg2, {
|
||||
if(stg != stg2 && stg->id == stg2->id) {
|
||||
log_fatal("Duplicate ID %X in stages array, indices: %i, %i", stg->id, i, j);
|
||||
}
|
||||
});
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void stage_free_array(void) {
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
free(stg->title);
|
||||
free(stg->subtitle);
|
||||
free(stg->progress);
|
||||
});
|
||||
|
||||
dynarray_free_data(&stages);
|
||||
}
|
||||
|
||||
StageInfo* stage_get(uint16_t n) {
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
if(stg->id == n) {
|
||||
return stg;
|
||||
}
|
||||
});
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StageInfo* stage_get_by_spellcard(AttackInfo *spell, Difficulty diff) {
|
||||
if(!spell) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dynarray_foreach_elem(&stages, StageInfo *stg, {
|
||||
if(stg->spell == spell && stg->difficulty == diff) {
|
||||
return stg;
|
||||
}
|
||||
});
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StageProgress* stage_get_progress_from_info(StageInfo *stage, Difficulty diff, bool allocate) {
|
||||
// D_Any stages will have a separate StageProgress for every selectable difficulty.
|
||||
// Stages with a fixed difficulty setting (spellpractice, extra stage...) obviously get just one and the diff parameter is ignored.
|
||||
|
||||
// This stuff must stay around until progress_save(), which happens on shutdown.
|
||||
// So do NOT try to free any pointers this function returns, that will fuck everything up.
|
||||
|
||||
if(!stage) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool fixed_diff = (stage->difficulty != D_Any);
|
||||
|
||||
if(!fixed_diff && (diff < D_Easy || diff > D_Lunatic)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!stage->progress) {
|
||||
if(!allocate) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t allocsize = sizeof(StageProgress) * (fixed_diff ? 1 : NUM_SELECTABLE_DIFFICULTIES);
|
||||
stage->progress = malloc(allocsize);
|
||||
memset(stage->progress, 0, allocsize);
|
||||
}
|
||||
|
||||
return stage->progress + (fixed_diff ? 0 : diff - D_Easy);
|
||||
}
|
||||
|
||||
StageProgress* stage_get_progress(uint16_t id, Difficulty diff, bool allocate) {
|
||||
return stage_get_progress_from_info(stage_get(id), diff, allocate);
|
||||
}
|
||||
#include "stageinfo.h"
|
||||
|
||||
static void stage_start(StageInfo *stage) {
|
||||
global.timer = 0;
|
||||
|
@ -680,7 +502,7 @@ void stage_finish(int gameover) {
|
|||
prev_gameover != GAMEOVER_SCORESCREEN &&
|
||||
(gameover == GAMEOVER_SCORESCREEN || gameover == GAMEOVER_WIN)
|
||||
) {
|
||||
StageProgress *p = stage_get_progress_from_info(global.stage, global.diff, true);
|
||||
StageProgress *p = stageinfo_get_progress(global.stage, global.diff, true);
|
||||
|
||||
if(p) {
|
||||
++p->num_cleared;
|
||||
|
@ -775,7 +597,7 @@ static void stage_give_clear_bonus(const StageInfo *stage, StageClearBonus *bonu
|
|||
|
||||
// FIXME: this is clunky...
|
||||
if(!global.is_practice_mode && stage->type == STAGE_STORY) {
|
||||
StageInfo *next = stage_get(stage->id + 1);
|
||||
StageInfo *next = stageinfo_get_by_id(stage->id + 1);
|
||||
|
||||
if(next == NULL || next->type != STAGE_STORY) {
|
||||
bonus->all_clear = true;
|
||||
|
@ -967,7 +789,7 @@ void stage_enter(StageInfo *stage, CallChain next) {
|
|||
log_debug("Start time: %"PRIu64, start_time);
|
||||
log_debug("Random seed: 0x%"PRIx64, seed);
|
||||
|
||||
StageProgress *p = stage_get_progress_from_info(stage, global.diff, true);
|
||||
StageProgress *p = stageinfo_get_progress(stage, global.diff, true);
|
||||
|
||||
if(p) {
|
||||
log_debug("You played this stage %u times", p->num_played);
|
||||
|
@ -980,7 +802,7 @@ void stage_enter(StageInfo *stage, CallChain next) {
|
|||
ReplayStage *stg = global.replay_stage;
|
||||
|
||||
assert(stg != NULL);
|
||||
assert(stage_get(stg->stage) == stage);
|
||||
assert(stageinfo_get_by_id(stg->stage) == stage);
|
||||
|
||||
rng_seed(&global.rand_game, stg->rng_seed);
|
||||
|
||||
|
|
63
src/stage.h
63
src/stage.h
|
@ -19,6 +19,7 @@
|
|||
#include "dialog.h"
|
||||
#include "coroutine.h"
|
||||
#include "dynarray.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
/* taisei's strange macro language.
|
||||
*
|
||||
|
@ -60,51 +61,6 @@
|
|||
#define FROM_TO_SND(snd,start,end,step) PLAY_FOR(snd,start,end); FROM_TO(start,end,step)
|
||||
#define FROM_TO_INT_SND(snd,start,end,step,dur,istep) FROM_TO_INT(start,end,step,dur,2) { play_loop(snd); }FROM_TO_INT(start,end,step,dur,istep)
|
||||
|
||||
typedef void (*StageProc)(void);
|
||||
typedef bool (*ShaderRule)(Framebuffer*); // true = drawn to color buffer
|
||||
|
||||
// two highest bits of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
|
||||
#define STAGE_SPELL_BIT 0x8000
|
||||
#define STAGE_EXTRASPELL_BIT 0x4000
|
||||
|
||||
typedef enum StageType {
|
||||
STAGE_STORY = 1,
|
||||
STAGE_EXTRA,
|
||||
STAGE_SPELL,
|
||||
STAGE_SPECIAL,
|
||||
} StageType;
|
||||
|
||||
typedef struct StageProcs StageProcs;
|
||||
|
||||
struct StageProcs {
|
||||
StageProc begin;
|
||||
StageProc preload;
|
||||
StageProc end;
|
||||
StageProc draw;
|
||||
StageProc event;
|
||||
StageProc update;
|
||||
ShaderRule *shader_rules;
|
||||
ShaderRule *postprocess_rules;
|
||||
StageProcs *spellpractice_procs;
|
||||
};
|
||||
|
||||
typedef struct StageInfo {
|
||||
uint16_t id; // must match type of ReplayStage.stage in replay.h
|
||||
StageProcs *procs;
|
||||
StageType type;
|
||||
char *title;
|
||||
char *subtitle;
|
||||
AttackInfo *spell;
|
||||
Difficulty difficulty;
|
||||
|
||||
// Do NOT access this directly!
|
||||
// Use stage_get_progress or stage_get_progress_from_info, which will lazy-initialize it and pick the correct offset.
|
||||
StageProgress *progress;
|
||||
} StageInfo;
|
||||
|
||||
typedef DYNAMIC_ARRAY(StageInfo) StageInfoArray;
|
||||
extern StageInfoArray stages;
|
||||
|
||||
typedef struct StageClearBonus {
|
||||
uint64_t base;
|
||||
uint64_t lives;
|
||||
|
@ -114,15 +70,6 @@ typedef struct StageClearBonus {
|
|||
bool all_clear;
|
||||
} StageClearBonus;
|
||||
|
||||
StageInfo* stage_get(uint16_t); // NOTE: This returns the stage BY ID, not by the array index!
|
||||
StageInfo* stage_get_by_spellcard(AttackInfo *spell, Difficulty diff);
|
||||
|
||||
StageProgress* stage_get_progress(uint16_t id, Difficulty diff, bool allocate);
|
||||
StageProgress* stage_get_progress_from_info(StageInfo *stage, Difficulty diff, bool allocate);
|
||||
|
||||
void stage_init_array(void);
|
||||
void stage_free_array(void);
|
||||
|
||||
void stage_enter(StageInfo *stage, CallChain next);
|
||||
void stage_finish(int gameover);
|
||||
|
||||
|
@ -164,12 +111,4 @@ DECLARE_EXTERN_TASK(stage_bookmark, { const char *name; });
|
|||
#define STAGE_BOOKMARK_DELAYED(delay, name) ((void)0)
|
||||
#endif
|
||||
|
||||
#include "stages/stage1.h"
|
||||
#include "stages/stage2.h"
|
||||
#include "stages/stage3.h"
|
||||
#include "stages/stage4.h"
|
||||
#include "stages/stage5.h"
|
||||
#include "stages/stage6.h"
|
||||
#include "stages/extra.h"
|
||||
|
||||
#endif // IGUARD_stage_h
|
||||
|
|
227
src/stageinfo.c
Normal file
227
src/stageinfo.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* 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 "stageinfo.h"
|
||||
|
||||
#include "stages/stage1.h"
|
||||
#include "stages/stage2.h"
|
||||
#include "stages/stage3.h"
|
||||
#include "stages/stage4.h"
|
||||
#include "stages/stage5.h"
|
||||
#include "stages/stage6.h"
|
||||
#include "stages/extra.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPSTEST
|
||||
#include "stages/dpstest.h"
|
||||
|
||||
#define COROTEST
|
||||
#include "stages/corotest.h"
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
DYNAMIC_ARRAY(StageInfo) stages;
|
||||
} stageinfo;
|
||||
|
||||
static void add_stage(
|
||||
uint16_t id,
|
||||
StageProcs *procs,
|
||||
StageType type,
|
||||
const char *title,
|
||||
const char *subtitle,
|
||||
AttackInfo *spell,
|
||||
Difficulty diff
|
||||
) {
|
||||
StageInfo *stg = dynarray_append(&stageinfo.stages);
|
||||
stg->id = id;
|
||||
stg->procs = procs;
|
||||
stg->type = type;
|
||||
stralloc(&stg->title, title);
|
||||
stralloc(&stg->subtitle, subtitle);
|
||||
stg->spell = spell;
|
||||
stg->difficulty = diff;
|
||||
}
|
||||
|
||||
static void add_spellpractice_stage(
|
||||
StageInfo *s,
|
||||
AttackInfo *a,
|
||||
int *spellnum,
|
||||
uint16_t spellbits,
|
||||
Difficulty diff
|
||||
) {
|
||||
uint16_t id = spellbits | a->idmap[diff - D_Easy] | (s->id << 8);
|
||||
|
||||
char *title = strfmt("Spell %d", ++(*spellnum));
|
||||
char *subtitle = strjoin(a->name, " ~ ", difficulty_name(diff), NULL);
|
||||
|
||||
add_stage(id, s->procs->spellpractice_procs, STAGE_SPELL, title, subtitle, a, diff);
|
||||
|
||||
free(title);
|
||||
free(subtitle);
|
||||
}
|
||||
|
||||
static void add_spellpractice_stages(
|
||||
int *spellnum,
|
||||
bool (*filter)(AttackInfo*),
|
||||
uint16_t spellbits
|
||||
) {
|
||||
for(int i = 0 ;; ++i) {
|
||||
StageInfo *s = dynarray_get_ptr(&stageinfo.stages, i);
|
||||
|
||||
if(s->type == STAGE_SPELL || !s->spell) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(AttackInfo *a = s->spell; a->name; ++a) {
|
||||
if(!filter(a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(Difficulty diff = D_Easy; diff < D_Easy + NUM_SELECTABLE_DIFFICULTIES; ++diff) {
|
||||
if(a->idmap[diff - D_Easy] >= 0) {
|
||||
add_spellpractice_stage(s, a, spellnum, spellbits, diff);
|
||||
|
||||
// stages may have gotten realloc'd, so we must update the pointer
|
||||
s = dynarray_get_ptr(&stageinfo.stages, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool spellfilter_normal(AttackInfo *spell) {
|
||||
return spell->type != AT_ExtraSpell;
|
||||
}
|
||||
|
||||
static bool spellfilter_extra(AttackInfo *spell) {
|
||||
return spell->type == AT_ExtraSpell;
|
||||
}
|
||||
|
||||
void stageinfo_init(void) {
|
||||
int spellnum = 0;
|
||||
|
||||
// id procs type title subtitle spells diff
|
||||
add_stage(1, &stage1_procs, STAGE_STORY, "Stage 1", "Misty Lake", (AttackInfo*)&stage1_spells, D_Any);
|
||||
add_stage(2, &stage2_procs, STAGE_STORY, "Stage 2", "Walk Along the Border", (AttackInfo*)&stage2_spells, D_Any);
|
||||
add_stage(3, &stage3_procs, STAGE_STORY, "Stage 3", "Through the Tunnel of Light", (AttackInfo*)&stage3_spells, D_Any);
|
||||
add_stage(4, &stage4_procs, STAGE_STORY, "Stage 4", "Forgotten Mansion", (AttackInfo*)&stage4_spells, D_Any);
|
||||
add_stage(5, &stage5_procs, STAGE_STORY, "Stage 5", "Climbing the Tower of Babel", (AttackInfo*)&stage5_spells, D_Any);
|
||||
add_stage(6, &stage6_procs, STAGE_STORY, "Stage 6", "Roof of the World", (AttackInfo*)&stage6_spells, D_Any);
|
||||
|
||||
#ifdef DPSTEST
|
||||
add_stage(0x40|0, &stage_dpstest_single_procs, STAGE_SPECIAL, "DPS Test", "Single target", NULL, D_Normal);
|
||||
add_stage(0x40|1, &stage_dpstest_multi_procs, STAGE_SPECIAL, "DPS Test", "Multiple targets", NULL, D_Normal);
|
||||
add_stage(0x40|2, &stage_dpstest_boss_procs, STAGE_SPECIAL, "DPS Test", "Boss", NULL, D_Normal);
|
||||
#endif
|
||||
|
||||
// generate spellpractice stages
|
||||
add_spellpractice_stages(&spellnum, spellfilter_normal, STAGE_SPELL_BIT);
|
||||
add_spellpractice_stages(&spellnum, spellfilter_extra, STAGE_SPELL_BIT | STAGE_EXTRASPELL_BIT);
|
||||
|
||||
#ifdef SPELL_BENCHMARK
|
||||
add_spellpractice_stage(dynarray_get_ptr(&stageinfo.stages, 0), &stage1_spell_benchmark, &spellnum, STAGE_SPELL_BIT, D_Extra);
|
||||
#endif
|
||||
|
||||
#ifdef COROTEST
|
||||
add_stage(0xC0, &corotest_procs, STAGE_SPECIAL, "Coroutines!", "wow such concurrency very async", NULL, D_Any);
|
||||
#endif
|
||||
|
||||
add_stage(0xC1, &extra_procs, STAGE_SPECIAL, "Extra Stage", "Descent into Madness", NULL, D_Extra);
|
||||
|
||||
dynarray_compact(&stageinfo.stages);
|
||||
|
||||
#ifdef DEBUG
|
||||
dynarray_foreach(&stageinfo.stages, int i, StageInfo *stg, {
|
||||
if(stg->type == STAGE_SPELL && !(stg->id & STAGE_SPELL_BIT)) {
|
||||
log_fatal("Spell stage has an ID without the spell bit set: 0x%04x", stg->id);
|
||||
}
|
||||
|
||||
dynarray_foreach(&stageinfo.stages, int j, StageInfo *stg2, {
|
||||
if(stg != stg2 && stg->id == stg2->id) {
|
||||
log_fatal("Duplicate ID %X in stages array, indices: %i, %i", stg->id, i, j);
|
||||
}
|
||||
});
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void stageinfo_shutdown(void) {
|
||||
dynarray_foreach_elem(&stageinfo.stages, StageInfo *stg, {
|
||||
free(stg->title);
|
||||
free(stg->subtitle);
|
||||
free(stg->progress);
|
||||
});
|
||||
|
||||
dynarray_free_data(&stageinfo.stages);
|
||||
}
|
||||
|
||||
size_t stageinfo_get_num_stages(void) {
|
||||
return stageinfo.stages.num_elements;
|
||||
}
|
||||
|
||||
StageInfo *stageinfo_get_by_index(size_t index) {
|
||||
return dynarray_get_ptr(&stageinfo.stages, index);
|
||||
}
|
||||
|
||||
StageInfo *stageinfo_get_by_id(uint16_t n) {
|
||||
// TODO speed this up (use a hashtable maybe)
|
||||
|
||||
dynarray_foreach_elem(&stageinfo.stages, StageInfo *stg, {
|
||||
if(stg->id == n) {
|
||||
return stg;
|
||||
}
|
||||
});
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StageInfo *stageinfo_get_by_spellcard(AttackInfo *spell, Difficulty diff) {
|
||||
if(!spell) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dynarray_foreach_elem(&stageinfo.stages, StageInfo *stg, {
|
||||
if(stg->spell == spell && stg->difficulty == diff) {
|
||||
return stg;
|
||||
}
|
||||
});
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StageProgress *stageinfo_get_progress(StageInfo *stage, Difficulty diff, bool allocate) {
|
||||
// D_Any stages will have a separate StageProgress for every selectable difficulty.
|
||||
// Stages with a fixed difficulty setting (spellpractice, extra stage...) obviously get just one and the diff parameter is ignored.
|
||||
|
||||
// This stuff must stay around until progress_save(), which happens on shutdown.
|
||||
// So do NOT try to free any pointers this function returns, that will fuck everything up.
|
||||
|
||||
bool fixed_diff = (stage->difficulty != D_Any);
|
||||
|
||||
if(!fixed_diff && (diff < D_Easy || diff > D_Lunatic)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!stage->progress) {
|
||||
if(!allocate) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t allocsize = sizeof(StageProgress) * (fixed_diff ? 1 : NUM_SELECTABLE_DIFFICULTIES);
|
||||
stage->progress = malloc(allocsize);
|
||||
memset(stage->progress, 0, allocsize);
|
||||
}
|
||||
|
||||
return stage->progress + (fixed_diff ? 0 : diff - D_Easy);
|
||||
}
|
||||
|
||||
StageProgress *stageinfo_get_progress_by_id(uint16_t id, Difficulty diff, bool allocate) {
|
||||
return stageinfo_get_progress(stageinfo_get_by_id(id), diff, allocate);
|
||||
}
|
72
src/stageinfo.h
Normal file
72
src/stageinfo.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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_stageinfo_h
|
||||
#define IGUARD_stageinfo_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
#include "difficulty.h"
|
||||
#include "boss.h"
|
||||
#include "progress.h"
|
||||
|
||||
typedef void (*StageProc)(void);
|
||||
typedef bool (*ShaderRule)(Framebuffer*); // true = drawn to color buffer
|
||||
|
||||
// two highest bits of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
|
||||
#define STAGE_SPELL_BIT 0x8000
|
||||
#define STAGE_EXTRASPELL_BIT 0x4000
|
||||
|
||||
typedef enum StageType {
|
||||
STAGE_STORY = 1,
|
||||
STAGE_EXTRA,
|
||||
STAGE_SPELL,
|
||||
STAGE_SPECIAL,
|
||||
} StageType;
|
||||
|
||||
typedef struct StageProcs StageProcs;
|
||||
struct StageProcs {
|
||||
StageProc begin;
|
||||
StageProc preload;
|
||||
StageProc end;
|
||||
StageProc draw;
|
||||
StageProc event;
|
||||
StageProc update;
|
||||
ShaderRule *shader_rules;
|
||||
ShaderRule *postprocess_rules;
|
||||
StageProcs *spellpractice_procs;
|
||||
};
|
||||
|
||||
typedef struct StageInfo {
|
||||
uint16_t id; // must match type of ReplayStage.stage in replay.h
|
||||
StageProcs *procs;
|
||||
StageType type;
|
||||
char *title;
|
||||
char *subtitle;
|
||||
AttackInfo *spell;
|
||||
Difficulty difficulty;
|
||||
|
||||
// Do NOT access this directly!
|
||||
// Use stage_get_progress or stage_get_progress_from_info, which will lazy-initialize it and pick the correct offset.
|
||||
StageProgress *progress;
|
||||
} StageInfo;
|
||||
|
||||
size_t stageinfo_get_num_stages(void);
|
||||
|
||||
StageInfo *stageinfo_get_by_index(size_t index);
|
||||
StageInfo *stageinfo_get_by_id(uint16_t id);
|
||||
StageInfo *stageinfo_get_by_spellcard(AttackInfo *spell, Difficulty diff);
|
||||
|
||||
StageProgress *stageinfo_get_progress(StageInfo *stageinfo, Difficulty diff, bool allocate);
|
||||
StageProgress *stageinfo_get_progress_by_id(uint16_t id, Difficulty diff, bool allocate);
|
||||
|
||||
void stageinfo_init(void);
|
||||
void stageinfo_shutdown(void);
|
||||
|
||||
#endif // IGUARD_stageinfo_h
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern StageProcs corotest_procs;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern StageProcs stage_dpstest_single_procs;
|
||||
extern StageProcs stage_dpstest_multi_procs;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "stagedraw.h"
|
||||
#include "resource/model.h"
|
||||
#include "stagetext.h"
|
||||
#include "stageutils.h"
|
||||
|
||||
TASK(glider_bullet, {
|
||||
cmplx pos; double dir; double spacing; int interval;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern StageProcs extra_procs;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
#if defined(DEBUG) && !defined(SPELL_BENCHMARK)
|
||||
#define SPELL_BENCHMARK
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "stage1_events.h"
|
||||
#include "stage1.h"
|
||||
#include "global.h"
|
||||
#include "stagetext.h"
|
||||
#include "common_tasks.h"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern struct stage2_spells_s {
|
||||
// this struct must contain only fields of type AttackInfo
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "stage2_events.h"
|
||||
#include "stage2.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "enemy.h"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern struct stage3_spells_s {
|
||||
// this struct must contain only fields of type AttackInfo
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "stage3_events.h"
|
||||
#include "stage3.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "enemy.h"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "stageinfo.h"
|
||||
|
||||
extern struct stage4_spells_s {
|
||||
// this struct must contain only fields of type AttackInfo
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "stage4_events.h"
|
||||
#include "stage4.h"
|
||||