mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 03:55:11 +00:00
951 lines
38 KiB
C++
951 lines
38 KiB
C++
#include "dynos.cpp.h"
|
|
extern "C" {
|
|
#include "game/segment2.h"
|
|
#include "game/save_file.h"
|
|
#include "levels/scripts.h"
|
|
#include "pc/lua/utils/smlua_level_utils.h"
|
|
|
|
#ifdef VERSION_EU
|
|
#include "eu_translation.h"
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Const
|
|
//
|
|
|
|
extern "C" {
|
|
extern const BehaviorScript *sWarpBhvSpawnTable[];
|
|
#include "engine/level_script.h"
|
|
}
|
|
|
|
#define DYNOS_LEVEL_TEXT_EMPTY ""
|
|
#define DYNOS_LEVEL_TEXT_CASTLE "CASTLE"
|
|
#define DYNOS_LEVEL_TEXT_BOWSER_1 "BOWSER 1"
|
|
#define DYNOS_LEVEL_TEXT_BOWSER_2 "BOWSER 2"
|
|
#define DYNOS_LEVEL_TEXT_BOWSER_3 "BOWSER 3"
|
|
#define DYNOS_LEVEL_TEXT_100_COINS_STAR "100 COINS STAR"
|
|
#define DYNOS_LEVEL_TEXT_RED_COINS_STAR "RED COINS STAR"
|
|
#define DYNOS_LEVEL_TEXT_ONE_SECRET_STAR "ONE OF THE CASTLE'S SECRET STARS!"
|
|
|
|
static void SetConvertedTextToBuffer(u8 *aBuffer, const char *aText) {
|
|
u8 *_ConvertedText = DynOS_String_Convert(aText, false);
|
|
memcpy(aBuffer, _ConvertedText, DynOS_String_Length(_ConvertedText) + 1);
|
|
}
|
|
|
|
//
|
|
// Data
|
|
//
|
|
|
|
struct DynosWarp {
|
|
/* 0 */ s16 mArea = 0;
|
|
/* 1 */ s16 mId = 0;
|
|
/* 2 */ s16 mType = -1;
|
|
/* 3 */ s16 mPosX = 0;
|
|
/* 4 */ s16 mPosY = 0;
|
|
/* 5 */ s16 mPosZ = 0;
|
|
/* 6 */ s16 mAngle = 0;
|
|
/* 7 */ s16 mDestLevel = 0;
|
|
/* 8 */ s16 mDestArea = 0;
|
|
/* 9 */ s16 mDestId = 0;
|
|
};
|
|
|
|
struct DynosLevelScript {
|
|
void *mLevelScript;
|
|
s32 mModIndex;
|
|
};
|
|
|
|
#define DYNOS_LEVEL_MOD_INDEX_VANILLA (-1)
|
|
|
|
static DynosLevelScript sDynosLevelScripts[LEVEL_COUNT] = { { NULL, DYNOS_LEVEL_MOD_INDEX_VANILLA } };
|
|
static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL };
|
|
static Array<DynosWarp> sDynosLevelWarps[LEVEL_COUNT] = { Array<DynosWarp>() };
|
|
static Array<s32> sDynosLevelList = Array<s32>(); // Ordered by Course Id, COURSE_NONE excluded
|
|
|
|
u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) {
|
|
u64 _Offset = (((aOffset) & 3llu) | (((aOffset) & ~3llu) << (sizeof(void *) >> 3llu)));
|
|
return *((u64 *) (u64(aCmd) + _Offset));
|
|
}
|
|
|
|
void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) {
|
|
u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu)));
|
|
return (void *) (u64(aCmd) + _Offset);
|
|
}
|
|
|
|
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
|
|
|
|
//
|
|
// Init
|
|
//
|
|
|
|
static s32 DynOS_Level_PreprocessMasterScript(u8 aType, void *aCmd) {
|
|
static bool sDynosScriptExecLevelTable = false;
|
|
static s32 sDynosLevelNum = -1;
|
|
|
|
if (!sDynosScriptExecLevelTable) {
|
|
|
|
// JUMP_LINK
|
|
if (aType == 0x06) {
|
|
sDynosScriptExecLevelTable = true;
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
// JUMP_IF
|
|
if (aType == 0x0C) {
|
|
sDynosLevelNum = (s32) DynOS_Level_CmdGet(aCmd, 0x04);
|
|
return 0;
|
|
}
|
|
|
|
// EXECUTE
|
|
if (aType == 0x00) {
|
|
void *_Script = (void *) DynOS_Level_CmdGet(aCmd, 0x0C);
|
|
if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum].mLevelScript) {
|
|
sDynosLevelScripts[sDynosLevelNum].mLevelScript = _Script;
|
|
sDynosLevelScripts[sDynosLevelNum].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
|
|
sDynosLevelScriptsOriginal[sDynosLevelNum] = _Script;
|
|
}
|
|
sDynosLevelNum = -1;
|
|
return 2;
|
|
}
|
|
|
|
// EXIT
|
|
if (aType == 0x02) {
|
|
return 3;
|
|
}
|
|
|
|
// SLEEP
|
|
if (aType == 0x03) {
|
|
return 3;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static s32 sDynosCurrentLevelNum;
|
|
static s32 DynOS_Level_PreprocessScript(u8 aType, void *aCmd) {
|
|
static u8 sDynosAreaIndex = 0;
|
|
static auto _GetWarpStruct = [](u8 aArea, u8 aId) -> DynosWarp * {
|
|
for (s32 i = 0; i != sDynosLevelWarps[sDynosCurrentLevelNum].Count(); ++i) {
|
|
if (sDynosLevelWarps[sDynosCurrentLevelNum][i].mArea == aArea &&
|
|
sDynosLevelWarps[sDynosCurrentLevelNum][i].mId == aId) {
|
|
return &sDynosLevelWarps[sDynosCurrentLevelNum][i];
|
|
}
|
|
}
|
|
DynosWarp _Warp;
|
|
_Warp.mArea = aArea;
|
|
_Warp.mId = aId;
|
|
sDynosLevelWarps[sDynosCurrentLevelNum].Add(_Warp);
|
|
return &sDynosLevelWarps[sDynosCurrentLevelNum][sDynosLevelWarps[sDynosCurrentLevelNum].Count() - 1];
|
|
};
|
|
|
|
// AREA
|
|
if (aType == 0x1F) {
|
|
sDynosAreaIndex = (u8) DynOS_Level_CmdGet(aCmd, 2);
|
|
}
|
|
|
|
// OBJECT
|
|
else if (aType == 0x24) {
|
|
const BehaviorScript *bhv = (const BehaviorScript *) DynOS_Level_CmdGet(aCmd, 20);
|
|
for (s32 i = 0; i < 20; ++i) {
|
|
if (sWarpBhvSpawnTable[i] == bhv) {
|
|
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, ((((u32) DynOS_Level_CmdGet(aCmd, 16)) >> 16) & 0xFF));
|
|
if (_Warp->mType == -1) {
|
|
_Warp->mType = i;
|
|
_Warp->mPosX = (s16) DynOS_Level_CmdGet(aCmd, 4);
|
|
_Warp->mPosY = (s16) DynOS_Level_CmdGet(aCmd, 6);
|
|
_Warp->mPosZ = (s16) DynOS_Level_CmdGet(aCmd, 8);
|
|
_Warp->mAngle = (s16)((((s32)((s16) DynOS_Level_CmdGet(aCmd, 12))) * 0x8000) / 180);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// WARP_NODE
|
|
else if (aType == 0x26) {
|
|
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, (u8) DynOS_Level_CmdGet(aCmd, 2));
|
|
if (_Warp->mDestLevel == 0) {
|
|
_Warp->mDestLevel = (u8) DynOS_Level_CmdGet(aCmd, 3);
|
|
_Warp->mDestArea = (u8) DynOS_Level_CmdGet(aCmd, 4);
|
|
_Warp->mDestId = (u8) DynOS_Level_CmdGet(aCmd, 5);
|
|
}
|
|
}
|
|
|
|
// PAINTING_WARP_NODE
|
|
else if (aType == 0x27) {
|
|
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, (u8) DynOS_Level_CmdGet(aCmd, 2));
|
|
if (_Warp->mDestLevel == 0) {
|
|
_Warp->mDestLevel = (u8) DynOS_Level_CmdGet(aCmd, 3);
|
|
_Warp->mDestArea = (u8) DynOS_Level_CmdGet(aCmd, 4);
|
|
_Warp->mDestId = (u8) DynOS_Level_CmdGet(aCmd, 5);
|
|
}
|
|
}
|
|
|
|
// SLEEP
|
|
// SLEEP_BEFORE_EXIT
|
|
else if (aType == 0x03 || aType == 0x04) {
|
|
return 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Runs only once
|
|
static void DynOS_Level_Init() {
|
|
static bool sInited = false;
|
|
if (!sInited) {
|
|
|
|
// Level scripts
|
|
DynOS_Level_ParseScript(level_main_scripts_entry, DynOS_Level_PreprocessMasterScript);
|
|
|
|
// Level warps
|
|
for (sDynosCurrentLevelNum = 0; sDynosCurrentLevelNum != LEVEL_COUNT; ++sDynosCurrentLevelNum) {
|
|
if (sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript) {
|
|
DynOS_Level_ParseScript(sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript, DynOS_Level_PreprocessScript);
|
|
}
|
|
}
|
|
|
|
// Level list ordered by course id
|
|
for (s32 i = COURSE_MIN; i <= COURSE_MAX; ++i) {
|
|
if (i == COURSE_CAKE_END) continue;
|
|
for (s32 j = 1; j != LEVEL_COUNT; ++j) {
|
|
if (get_level_course_num(j - 1) == i) {
|
|
sDynosLevelList.Add(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Done
|
|
sInited = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Common
|
|
//
|
|
|
|
s32 DynOS_Level_GetCount() {
|
|
DynOS_Level_Init();
|
|
return sDynosLevelList.Count();
|
|
}
|
|
|
|
const s32 *DynOS_Level_GetList() {
|
|
DynOS_Level_Init();
|
|
return sDynosLevelList.begin();
|
|
}
|
|
|
|
s32 DynOS_Level_GetCourse(s32 aLevel) {
|
|
u32 index = aLevel - 1;
|
|
if (index >= LEVEL_COUNT) { return COURSE_NONE; }
|
|
return (s32) gLevelToCourseNumTable[index];
|
|
}
|
|
|
|
void DynOS_Level_Override(void* originalScript, void* newScript, s32 modIndex) {
|
|
for (s32 i = 0; i < LEVEL_COUNT; i++) {
|
|
if (sDynosLevelScripts[i].mLevelScript == originalScript) {
|
|
sDynosCurrentLevelNum = i;
|
|
sDynosLevelWarps[i].Clear();
|
|
DynOS_Level_ParseScript(newScript, DynOS_Level_PreprocessScript);
|
|
sDynosLevelScripts[i].mLevelScript = newScript;
|
|
sDynosLevelScripts[i].mModIndex = modIndex;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DynOS_Level_Unoverride() {
|
|
for (s32 i = 0; i < LEVEL_COUNT; i++) {
|
|
sDynosCurrentLevelNum = i;
|
|
sDynosLevelWarps[i].Clear();
|
|
sDynosLevelScripts[i].mLevelScript = sDynosLevelScriptsOriginal[i];
|
|
sDynosLevelScripts[i].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
|
|
DynOS_Level_ParseScript(sDynosLevelScripts[i].mLevelScript, DynOS_Level_PreprocessScript);
|
|
}
|
|
}
|
|
|
|
const void *DynOS_Level_GetScript(s32 aLevel) {
|
|
if (aLevel >= CUSTOM_LEVEL_NUM_START) {
|
|
struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
|
|
if (!info || !info->script) { return NULL; }
|
|
return info->script;
|
|
}
|
|
|
|
DynOS_Level_Init();
|
|
return sDynosLevelScripts[aLevel].mLevelScript;
|
|
}
|
|
|
|
s32 DynOS_Level_GetModIndex(s32 aLevel) {
|
|
if (aLevel >= CUSTOM_LEVEL_NUM_START) {
|
|
struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
|
|
if (!info || !info->script) { return DYNOS_LEVEL_MOD_INDEX_VANILLA; }
|
|
return info->modIndex;
|
|
}
|
|
|
|
DynOS_Level_Init();
|
|
return sDynosLevelScripts[aLevel].mModIndex;
|
|
}
|
|
|
|
bool DynOS_Level_IsVanillaLevel(s32 aLevel) {
|
|
if (aLevel >= 0 && aLevel < LEVEL_COUNT) {
|
|
return sDynosLevelScripts[aLevel].mLevelScript == sDynosLevelScriptsOriginal[aLevel];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Course name
|
|
//
|
|
|
|
const u8 *DynOS_Level_GetName(s32 aLevel, bool aDecaps, bool aAddCourseNumber) {
|
|
DynOS_Level_Init();
|
|
static u8 sBuffer[256];
|
|
memset(sBuffer, 0xFF, 256);
|
|
s32 _Course = DynOS_Level_GetCourse(aLevel);
|
|
|
|
// Level name
|
|
if (aLevel == LEVEL_BOWSER_1) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_1);
|
|
} else if (aLevel == LEVEL_BOWSER_2) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_2);
|
|
} else if (aLevel == LEVEL_BOWSER_3) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_3);
|
|
} else if (_Course < COURSE_BOB) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_CASTLE);
|
|
} else if (_Course >= COURSE_CAKE_END) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_CASTLE);
|
|
} else {
|
|
#ifdef VERSION_EU
|
|
const u8 *_CourseName = ((const u8 **) course_name_table_eu_en)[_Course - COURSE_BOB] + 3;
|
|
#else
|
|
const u8 *_CourseName = ((const u8 **) seg2_course_name_table)[_Course - COURSE_BOB] + 3;
|
|
#endif
|
|
memcpy(sBuffer, _CourseName, DynOS_String_Length(_CourseName));
|
|
}
|
|
|
|
// Decaps
|
|
if (aDecaps) {
|
|
DynOS_String_Decapitalize(sBuffer);
|
|
}
|
|
|
|
// Course number
|
|
if (aAddCourseNumber && (_Course >= COURSE_BOB) && (_Course <= COURSE_STAGES_MAX)) {
|
|
memmove(sBuffer + 5, sBuffer, DynOS_String_Length(sBuffer));
|
|
sBuffer[0] = ((_Course / 10) == 0 ? 158 : (_Course / 10));
|
|
sBuffer[1] = (_Course % 10);
|
|
sBuffer[2] = 158;
|
|
sBuffer[3] = 159;
|
|
sBuffer[4] = 158;
|
|
}
|
|
|
|
return sBuffer;
|
|
}
|
|
|
|
//
|
|
// Act/Star name
|
|
//
|
|
|
|
const u8 *DynOS_Level_GetActName(s32 aLevel, s32 aAct, bool aDecaps, bool aAddStarNumber) {
|
|
DynOS_Level_Init();
|
|
static u8 sBuffer[256];
|
|
memset(sBuffer, 0xFF, 256);
|
|
s32 _Course = DynOS_Level_GetCourse(aLevel);
|
|
|
|
// Star name
|
|
if (_Course < COURSE_BOB) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_ONE_SECRET_STAR);
|
|
} else if (aLevel == LEVEL_BITDW) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
|
} else if (aLevel == LEVEL_BITFS) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
|
} else if (aLevel == LEVEL_BITS) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
|
} else if (_Course > COURSE_STAGES_MAX) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_EMPTY);
|
|
} else if (aAct >= 7) {
|
|
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_100_COINS_STAR);
|
|
} else {
|
|
#ifdef VERSION_EU
|
|
const u8 *_ActName = ((const u8 **) act_name_table_eu_en)[(_Course - COURSE_BOB) * 6 + (aAct - 1)];
|
|
#else
|
|
const u8 *_ActName = ((const u8 **) seg2_act_name_table)[(_Course - COURSE_BOB) * 6 + (aAct - 1)];
|
|
#endif
|
|
memcpy(sBuffer, _ActName, DynOS_String_Length(_ActName));
|
|
}
|
|
|
|
// Decaps
|
|
if (aDecaps) {
|
|
DynOS_String_Decapitalize(sBuffer);
|
|
}
|
|
|
|
// Star number
|
|
if (aAddStarNumber && (_Course >= COURSE_BOB) && (_Course <= COURSE_STAGES_MAX)) {
|
|
memmove(sBuffer + 5, sBuffer, DynOS_String_Length(sBuffer));
|
|
sBuffer[0] = ((aAct / 10) == 0 ? 158 : (aAct / 10));
|
|
sBuffer[1] = (aAct % 10);
|
|
sBuffer[2] = 158;
|
|
sBuffer[3] = 159;
|
|
sBuffer[4] = 158;
|
|
}
|
|
|
|
return sBuffer;
|
|
}
|
|
|
|
const u8 *DynOS_Level_GetAreaName(s32 aLevel, s32 aArea, bool aDecaps) {
|
|
DynOS_Level_Init();
|
|
static const char *sAreaNamesPerLevel[][4] = {
|
|
{ "", "", "", "" },
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BoB */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WF */
|
|
{ "MAIN AREA", "SUNKEN SHIP", "NOT AVAILABLE", "NOT AVAILABLE" }, /* JRB */
|
|
{ "MAIN AREA", "COTTAGE SLIDE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* CCM */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BBH */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* HMC */
|
|
{ "MAIN AREA", "VOLCANO", "NOT AVAILABLE", "NOT AVAILABLE" }, /* LLL */
|
|
{ "MAIN AREA", "PYRAMID", "EYEROCK'S ROOM", "NOT AVAILABLE" }, /* SSL */
|
|
{ "MAIN AREA", "DOCKS", "NOT AVAILABLE", "NOT AVAILABLE" }, /* DDD */
|
|
{ "MAIN AREA", "IGLOO", "NOT AVAILABLE", "NOT AVAILABLE" }, /* SL */
|
|
{ "MAIN AREA", "DOWNTOWN", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WDW */
|
|
{ "MAIN AREA", "SECRET SLIDE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TTM */
|
|
{ "HUGE ISLAND", "TINY ISLAND", "WIGGLER'S ROOM", "NOT AVAILABLE" }, /* THI */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TTC */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* RR */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITDW */
|
|
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 1 */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITFS */
|
|
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 2 */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITS */
|
|
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 3 */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* PSS */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TOTWC */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* COTMC */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* VCUTM */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WMOTR */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* SA */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Castle grounds */
|
|
{ "FIRST FLOOR", "SECOND FLOOR", "BASEMENT", "NOT AVAILABLE" }, /* Castle inside */
|
|
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Castle courtyard */
|
|
{ "ENDING", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Ending */
|
|
};
|
|
static u8 sBuffer[256];
|
|
memset(sBuffer, 0xFF, 256);
|
|
|
|
// Area name
|
|
switch (aLevel) {
|
|
case LEVEL_BOB: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[1][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_WF: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[2][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_JRB: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[3][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_CCM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[4][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BBH: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[5][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_HMC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[6][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_LLL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[7][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_SSL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[8][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_DDD: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[9][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_SL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[10][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_WDW: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[11][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_TTM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[12][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_THI: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[13][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_TTC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[14][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_RR: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[15][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BITDW: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[16][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BOWSER_1: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[17][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BITFS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[18][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BOWSER_2: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[19][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BITS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[20][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_BOWSER_3: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[21][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_PSS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[22][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_TOTWC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[23][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_COTMC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[24][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_VCUTM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[25][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_WMOTR: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[26][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_SA: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[27][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_CASTLE_GROUNDS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[28][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_CASTLE: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[29][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_CASTLE_COURTYARD: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[30][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
case LEVEL_ENDING: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[31][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
default: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[0][MIN(MAX(aArea - 1, 0), 3)]); break;
|
|
}
|
|
|
|
// Decaps
|
|
if (aDecaps) {
|
|
DynOS_String_Decapitalize(sBuffer);
|
|
}
|
|
return sBuffer;
|
|
}
|
|
|
|
//
|
|
// Level Script Preprocessing
|
|
// By default,
|
|
// - Ifs are always true
|
|
// - Skips are always false
|
|
// - Loops break after the first loop
|
|
//
|
|
|
|
struct LvlCmd {
|
|
u8 mType;
|
|
u8 mSize;
|
|
};
|
|
|
|
struct Stack {
|
|
u64 mData[32];
|
|
s32 mBaseIndex;
|
|
s32 mTopIndex;
|
|
};
|
|
|
|
template <typename T>
|
|
static void StackPush(Stack& aStack, const T &aValue) {
|
|
if (aStack.mTopIndex >= 0) {
|
|
aStack.mData[aStack.mTopIndex] = u64(aValue);
|
|
aStack.mTopIndex++;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static T StackPop(Stack& aStack) {
|
|
if (aStack.mTopIndex <= 0) {
|
|
return (T) 0;
|
|
}
|
|
aStack.mTopIndex--;
|
|
return (T) aStack.mData[aStack.mTopIndex];
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdExecute(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
|
StackPush(aStack, aStack.mBaseIndex);
|
|
aStack.mBaseIndex = aStack.mTopIndex;
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 12);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdExitAndExecute(Stack &aStack, LvlCmd *aCmd) {
|
|
aStack.mTopIndex = aStack.mBaseIndex;
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 12);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdExit(Stack &aStack, LvlCmd *aCmd) {
|
|
aStack.mTopIndex = aStack.mBaseIndex;
|
|
aStack.mBaseIndex = StackPop<s32>(aStack);
|
|
return StackPop<LvlCmd *>(aStack);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSleep(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSleepBeforeExit(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJump(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 4);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpLink(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 4);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdReturn(Stack &aStack, UNUSED LvlCmd *aCmd) {
|
|
return StackPop<LvlCmd *>(aStack);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpLinkPushArg(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
|
StackPush(aStack, DynOS_Level_CmdGet(aCmd, 2));
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpRepeat(Stack &aStack, LvlCmd *aCmd) {
|
|
aStack.mTopIndex -= 2;
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoopBegin(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
|
StackPush(aStack, 0);
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoopUntil(Stack &aStack, LvlCmd *aCmd) {
|
|
aStack.mTopIndex -= 2;
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpIf(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize)); /* Not an error, that's intentional */
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 8);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpLinkIf(Stack &aStack, LvlCmd *aCmd) {
|
|
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
|
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 8);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSkipIf(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSkip(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSkipNop(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdCall(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdCallLoop(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetRegister(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdPushPool(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdPopPool(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadFixed(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadRaw(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadMIO0(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadMarioHead(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadMIO0Texture(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdInitLevel(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdClearLevel(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdAllocLevelPool(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdFreeLevelPool(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdBeginArea(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdEndArea(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadModelFromDL(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadModelFromGeo(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_Cmd23(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdMario(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdObject(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdWarpNode(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdInstantWarp(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetTerrainType(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdPaintingWarpNode(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_Cmd3A(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetWhirlpool(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetBlackout(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetGamma(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetTerrain(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetRooms(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdMacroObjects(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadArea(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdUnloadArea(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetMarioStartPos(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_Cmd2C(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_Cmd2D(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetTransition(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdNop(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdShowDialog(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetBackgroundMusic(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdSetMenuMusic(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdStopMusic(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdGetOrSet(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdAdvanceDemo(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdClearDemoPointer(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdPlaceObjectExt(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdPlaceObjectExt2(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdLoadModelFromGeoExt(Stack &aStack, LvlCmd *aCmd) {
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
static LvlCmd *DynOS_Level_CmdJumpArea(Stack &aStack, LvlCmd *aCmd, s32 (*aPreprocessFunction)(u8, void *)) {
|
|
DynOS_Level_ParseScript((const void *) DynOS_Level_CmdGet(aCmd, 8), aPreprocessFunction);
|
|
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
|
}
|
|
|
|
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) {
|
|
Stack _Stack;
|
|
_Stack.mBaseIndex = -1;
|
|
_Stack.mTopIndex = 0;
|
|
for (LvlCmd *_Cmd = (LvlCmd *) aScript; _Cmd != NULL;) {
|
|
u8 _CmdType = (_Cmd->mType & 0xFF);
|
|
s32 _Action = aPreprocessFunction(_CmdType, (void *) _Cmd);
|
|
switch (_Action) {
|
|
case 0:
|
|
switch (_CmdType) {
|
|
case 0x00: _Cmd = DynOS_Level_CmdExecute(_Stack, _Cmd); break;
|
|
case 0x01: _Cmd = DynOS_Level_CmdExitAndExecute(_Stack, _Cmd); break;
|
|
case 0x02: _Cmd = DynOS_Level_CmdExit(_Stack, _Cmd); break;
|
|
case 0x03: _Cmd = DynOS_Level_CmdSleep(_Stack, _Cmd); break;
|
|
case 0x04: _Cmd = DynOS_Level_CmdSleepBeforeExit(_Stack, _Cmd); break;
|
|
case 0x05: _Cmd = DynOS_Level_CmdJump(_Stack, _Cmd); break;
|
|
case 0x06: _Cmd = DynOS_Level_CmdJumpLink(_Stack, _Cmd); break;
|
|
case 0x07: _Cmd = DynOS_Level_CmdReturn(_Stack, _Cmd); break;
|
|
case 0x08: _Cmd = DynOS_Level_CmdJumpLinkPushArg(_Stack, _Cmd); break;
|
|
case 0x09: _Cmd = DynOS_Level_CmdJumpRepeat(_Stack, _Cmd); break;
|
|
case 0x0A: _Cmd = DynOS_Level_CmdLoopBegin(_Stack, _Cmd); break;
|
|
case 0x0B: _Cmd = DynOS_Level_CmdLoopUntil(_Stack, _Cmd); break;
|
|
case 0x0C: _Cmd = DynOS_Level_CmdJumpIf(_Stack, _Cmd); break;
|
|
case 0x0D: _Cmd = DynOS_Level_CmdJumpLinkIf(_Stack, _Cmd); break;
|
|
case 0x0E: _Cmd = DynOS_Level_CmdSkipIf(_Stack, _Cmd); break;
|
|
case 0x0F: _Cmd = DynOS_Level_CmdSkip(_Stack, _Cmd); break;
|
|
case 0x10: _Cmd = DynOS_Level_CmdSkipNop(_Stack, _Cmd); break;
|
|
case 0x11: _Cmd = DynOS_Level_CmdCall(_Stack, _Cmd); break;
|
|
case 0x12: _Cmd = DynOS_Level_CmdCallLoop(_Stack, _Cmd); break;
|
|
case 0x13: _Cmd = DynOS_Level_CmdSetRegister(_Stack, _Cmd); break;
|
|
case 0x14: _Cmd = DynOS_Level_CmdPushPool(_Stack, _Cmd); break;
|
|
case 0x15: _Cmd = DynOS_Level_CmdPopPool(_Stack, _Cmd); break;
|
|
case 0x16: _Cmd = DynOS_Level_CmdLoadFixed(_Stack, _Cmd); break;
|
|
case 0x17: _Cmd = DynOS_Level_CmdLoadRaw(_Stack, _Cmd); break;
|
|
case 0x18: _Cmd = DynOS_Level_CmdLoadMIO0(_Stack, _Cmd); break;
|
|
case 0x19: _Cmd = DynOS_Level_CmdLoadMarioHead(_Stack, _Cmd); break;
|
|
case 0x1A: _Cmd = DynOS_Level_CmdLoadMIO0Texture(_Stack, _Cmd); break;
|
|
case 0x1B: _Cmd = DynOS_Level_CmdInitLevel(_Stack, _Cmd); break;
|
|
case 0x1C: _Cmd = DynOS_Level_CmdClearLevel(_Stack, _Cmd); break;
|
|
case 0x1D: _Cmd = DynOS_Level_CmdAllocLevelPool(_Stack, _Cmd); break;
|
|
case 0x1E: _Cmd = DynOS_Level_CmdFreeLevelPool(_Stack, _Cmd); break;
|
|
case 0x1F: _Cmd = DynOS_Level_CmdBeginArea(_Stack, _Cmd); break;
|
|
case 0x20: _Cmd = DynOS_Level_CmdEndArea(_Stack, _Cmd); break;
|
|
case 0x21: _Cmd = DynOS_Level_CmdLoadModelFromDL(_Stack, _Cmd); break;
|
|
case 0x22: _Cmd = DynOS_Level_CmdLoadModelFromGeo(_Stack, _Cmd); break;
|
|
case 0x23: _Cmd = DynOS_Level_Cmd23(_Stack, _Cmd); break;
|
|
case 0x24: _Cmd = DynOS_Level_CmdObject(_Stack, _Cmd); break;
|
|
case 0x25: _Cmd = DynOS_Level_CmdMario(_Stack, _Cmd); break;
|
|
case 0x26: _Cmd = DynOS_Level_CmdWarpNode(_Stack, _Cmd); break;
|
|
case 0x27: _Cmd = DynOS_Level_CmdPaintingWarpNode(_Stack, _Cmd); break;
|
|
case 0x28: _Cmd = DynOS_Level_CmdInstantWarp(_Stack, _Cmd); break;
|
|
case 0x29: _Cmd = DynOS_Level_CmdLoadArea(_Stack, _Cmd); break;
|
|
case 0x2A: _Cmd = DynOS_Level_CmdUnloadArea(_Stack, _Cmd); break;
|
|
case 0x2B: _Cmd = DynOS_Level_CmdSetMarioStartPos(_Stack, _Cmd); break;
|
|
case 0x2C: _Cmd = DynOS_Level_Cmd2C(_Stack, _Cmd); break;
|
|
case 0x2D: _Cmd = DynOS_Level_Cmd2D(_Stack, _Cmd); break;
|
|
case 0x2E: _Cmd = DynOS_Level_CmdSetTerrain(_Stack, _Cmd); break;
|
|
case 0x2F: _Cmd = DynOS_Level_CmdSetRooms(_Stack, _Cmd); break;
|
|
case 0x30: _Cmd = DynOS_Level_CmdShowDialog(_Stack, _Cmd); break;
|
|
case 0x31: _Cmd = DynOS_Level_CmdSetTerrainType(_Stack, _Cmd); break;
|
|
case 0x32: _Cmd = DynOS_Level_CmdNop(_Stack, _Cmd); break;
|
|
case 0x33: _Cmd = DynOS_Level_CmdSetTransition(_Stack, _Cmd); break;
|
|
case 0x34: _Cmd = DynOS_Level_CmdSetBlackout(_Stack, _Cmd); break;
|
|
case 0x35: _Cmd = DynOS_Level_CmdSetGamma(_Stack, _Cmd); break;
|
|
case 0x36: _Cmd = DynOS_Level_CmdSetBackgroundMusic(_Stack, _Cmd); break;
|
|
case 0x37: _Cmd = DynOS_Level_CmdSetMenuMusic(_Stack, _Cmd); break;
|
|
case 0x38: _Cmd = DynOS_Level_CmdStopMusic(_Stack, _Cmd); break;
|
|
case 0x39: _Cmd = DynOS_Level_CmdMacroObjects(_Stack, _Cmd); break;
|
|
case 0x3A: _Cmd = DynOS_Level_Cmd3A(_Stack, _Cmd); break;
|
|
case 0x3B: _Cmd = DynOS_Level_CmdSetWhirlpool(_Stack, _Cmd); break;
|
|
case 0x3C: _Cmd = DynOS_Level_CmdGetOrSet(_Stack, _Cmd); break;
|
|
case 0x3D: _Cmd = DynOS_Level_CmdAdvanceDemo(_Stack, _Cmd); break;
|
|
case 0x3E: _Cmd = DynOS_Level_CmdClearDemoPointer(_Stack, _Cmd); break;
|
|
// coop
|
|
case 0x3F: _Cmd = DynOS_Level_CmdPlaceObjectExt(_Stack, _Cmd); break;
|
|
case 0x40: _Cmd = DynOS_Level_CmdPlaceObjectExt2(_Stack, _Cmd); break;
|
|
case 0x41: _Cmd = DynOS_Level_CmdLoadModelFromGeoExt(_Stack, _Cmd); break;
|
|
case 0x42: _Cmd = DynOS_Level_CmdJumpArea(_Stack, _Cmd, aPreprocessFunction); break;
|
|
} break;
|
|
|
|
case 1:
|
|
_Cmd = (LvlCmd *) DynOS_Level_CmdNext(_Cmd, _Cmd->mSize);
|
|
break;
|
|
|
|
case 2:
|
|
_Cmd = DynOS_Level_CmdReturn(_Stack, _Cmd);
|
|
break;
|
|
|
|
case 3:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Level Script Utilities
|
|
//
|
|
|
|
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
|
|
if (aLevel >= CUSTOM_LEVEL_NUM_START) {
|
|
struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
|
|
if (!info || !info->script) { return NULL; }
|
|
sDynosCurrentLevelNum = 1;
|
|
DynOS_Level_ParseScript(info->script, DynOS_Level_PreprocessScript);
|
|
for (const auto &_Warp : sDynosLevelWarps[1]) {
|
|
if (_Warp.mArea == aArea) {
|
|
if (_Warp.mId == aWarpId) {
|
|
return (s16 *) &_Warp;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
DynOS_Level_Init();
|
|
if (aLevel >= 0 && aLevel < LEVEL_COUNT) {
|
|
for (const auto &_Warp : sDynosLevelWarps[aLevel]) {
|
|
if (_Warp.mArea == aArea) {
|
|
if (_Warp.mId == aWarpId) {
|
|
return (s16 *) &_Warp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea) {
|
|
DynOS_Level_Init();
|
|
if (aLevel == LEVEL_TTM && aArea > 2) return NULL;
|
|
|
|
// override vanilla castle warps
|
|
if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE && aLevel >= 0 && aLevel < LEVEL_COUNT) {
|
|
extern const LevelScript level_castle_grounds_entry[];
|
|
extern const LevelScript level_castle_inside_entry[];
|
|
extern const LevelScript level_castle_courtyard_entry[];
|
|
if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_inside_entry) {
|
|
return DynOS_Level_GetWarp(aLevel, aArea, (aArea == 3) ? 0x00 : 0x01);
|
|
} else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_grounds_entry) {
|
|
return DynOS_Level_GetWarp(aLevel, aArea, 0x00);
|
|
} else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_courtyard_entry) {
|
|
return DynOS_Level_GetWarp(aLevel, aArea, 0x01);
|
|
}
|
|
}
|
|
|
|
return DynOS_Level_GetWarp(aLevel, aArea, 0x0A);
|
|
}
|
|
|
|
s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea) {
|
|
DynOS_Level_Init();
|
|
s16 *_Warp = DynOS_Level_GetWarp(aLevel, aArea, 0xF1);
|
|
if (!_Warp) _Warp = DynOS_Level_GetWarp(aLevel, aArea, 0xF3);
|
|
return _Warp;
|
|
}
|