custom level fixes and fixes from other pr (#483)

clean up custom level code
    fixed a bug where custom level course numbers weren't used by dynos warps
    removed a bunch of unused dynos code
    fix demos triggering incorrectly
    allowed the right Ctrl key to be used when opening the in game console
    fixed a softlock that was possible to experience when talking to the snowman in CCM
    fixed the bug where you can permanently lose your cap (bug created by my own PR from beta 32)
    fix the moderator feature I made a while back; I am amazed it even worked at all before
    fixed dynos warp initial actions being skipped (read ec8aabc for explanation)
    completely changed the way star names and course names work
This commit is contained in:
Isaac0-dev 2023-10-28 09:42:27 +10:00 committed by GitHub
parent ccace962a5
commit f07f5e5433
68 changed files with 1262 additions and 2866 deletions

View File

@ -166,7 +166,7 @@ def process_define(filename, line):
continue
p = re.sub(r'0x[a-fA-F0-9]+', '', p)
if re.search('[a-z]', p) != None and 'VERSION_TEXT' not in line:
if 'gCurrentObject' not in line:
if 'gCurrentObject' not in line and 'gNetworkType' not in line:
print('UNRECOGNIZED DEFINE: ' + line)
return None

View File

@ -102,12 +102,14 @@ override_disallowed_functions = {
"src/game/obj_behaviors.c": [ "debug_" ],
"src/game/obj_behaviors_2.c": [ "wiggler_jumped_on_attack_handler", "huge_goomba_weakly_attacked" ],
"src/game/spawn_sound.c": [ "spawner" ],
"src/game/level_info.h": [ "_name_table" ],
"src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field", "set_exclamation_box_new_contents", "get_exclamation_box_new_contents_pointer", "get_exclamation_box_new_contents_size" ],
"src/game/camera.h": [ "update_camera", "init_camera", "stub_camera", "^reset_camera", "move_point_along_spline" ],
"src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ],
"src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown"],
"src/pc/djui/djui_hud_utils.h": [ "djui_hud_render_texture", "djui_hud_render_texture_raw", "djui_hud_render_texture_tile", "djui_hud_render_texture_tile_raw" ],
"src/pc/lua/utils/smlua_level_utils.h": [ "smlua_level_util_reset" ],
"src/pc/lua/utils/smlua_text_utils.h": [ "smlua_text_utils_reset_all" ],
"src/pc/lua/utils/smlua_anim_utils.h": [ "smlua_anim_util_reset", "smlua_anim_util_register_animation" ],
"src/pc/network/lag_compensation.h": [ "lag_compensation_clear", "lag_compensation_store" ]
}

View File

@ -79,7 +79,7 @@ override_field_mutable = {
override_field_invisible = {
"Mod": [ "files" ],
"MarioState": [ "visibleToEnemies" ],
"NetworkPlayer": [ "gag"],
"NetworkPlayer": [ "gag", "moderator"],
"GraphNode": [ "_guard1", "_guard2" ],
}
@ -371,11 +371,11 @@ def build_struct(struct):
if sid in override_field_invisible:
if fid in override_field_invisible[sid]:
continue
version = None
row = []
startStr = ''
endStr = ' },'
if fid in override_field_version_excludes:

View File

@ -8190,6 +8190,22 @@ function smlua_audio_utils_reset_all()
-- ...
end
--- @param x number
--- @param y number
--- @param z number
--- @return Surface
function collision_find_ceil(x, y, z)
-- ...
end
--- @param x number
--- @param y number
--- @param z number
--- @return Surface
function collision_find_floor(x, y, z)
-- ...
end
--- @param startX number
--- @param startY number
--- @param startZ number
@ -8254,6 +8270,12 @@ function smlua_level_util_get_info(levelNum)
-- ...
end
--- @param courseNum integer
--- @return CustomLevelInfo
function smlua_level_util_get_info_from_course_num(courseNum)
-- ...
end
--- @param shortName string
--- @return CustomLevelInfo
function smlua_level_util_get_info_from_short_name(shortName)
@ -9096,6 +9118,35 @@ function spawn_sync_object(behaviorId, modelId, x, y, z, objSetupFunction)
-- ...
end
--- @param courseNum integer
--- @param actNum integer
--- @return string
function smlua_text_utils_act_name_get(courseNum, actNum)
-- ...
end
--- @param courseNum integer
--- @param actNum integer
--- @return boolean
function smlua_text_utils_act_name_is_modified(courseNum, actNum)
-- ...
end
--- @param courseNum integer
--- @param actNum integer
--- @param name string
--- @return nil
function smlua_text_utils_act_name_replace(courseNum, actNum, name)
-- ...
end
--- @param courseNum integer
--- @param actNum integer
--- @return nil
function smlua_text_utils_act_name_reset(courseNum, actNum)
-- ...
end
--- @param name string
--- @return nil
function smlua_text_utils_castle_secret_stars_replace(name)
@ -9115,6 +9166,31 @@ function smlua_text_utils_course_acts_replace(courseNum, courseName, act1, act2,
-- ...
end
--- @param courseNum integer
--- @return string
function smlua_text_utils_course_name_get(courseNum)
-- ...
end
--- @param courseNum integer
--- @return integer
function smlua_text_utils_course_name_mod_index(courseNum)
-- ...
end
--- @param courseNum integer
--- @param name string
--- @return nil
function smlua_text_utils_course_name_replace(courseNum, name)
-- ...
end
--- @param courseNum integer
--- @return nil
function smlua_text_utils_course_name_reset(courseNum)
-- ...
end
--- @param dialogId DialogId
--- @param unused integer
--- @param linesPerBox integer
@ -9138,11 +9214,6 @@ function smlua_text_utils_get_language()
-- ...
end
--- @return nil
function smlua_text_utils_reset_all()
-- ...
end
--- @param courseNum integer
--- @param courseName string
--- @return nil

View File

@ -12,7 +12,6 @@ void *dynos_swap_cmd(void *cmd);
// -- built in -- //
void *dynos_update_cmd(void *cmd);
void dynos_update_gfx();
void dynos_update_opt(void *pad);
s32 dynos_tex_import(void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize);
void dynos_gfx_swap_animations(void *ptr);
@ -59,7 +58,7 @@ const char* dynos_level_get_token(u32 index);
Trajectory* dynos_level_get_trajectory(const char* name);
void dynos_level_load_background(void *ptr);
u64 dynos_level_cmd_get(void *cmd, u64 offset);
void dynos_level_cmd_next(void *cmd, u64 cmdsize);
void dynos_level_cmd_next(void *cmd);
void dynos_level_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *));
void* dynos_level_get_script(s32 level);
s32 dynos_level_get_mod_index(s32 level);

View File

@ -656,6 +656,11 @@ struct BuiltinTexInfo {
s32 bitSize;
};
struct LvlCmd {
u8 mType;
u8 mSize;
};
//
// Utils
//
@ -783,23 +788,6 @@ void DynOS_Mod_Update();
void DynOS_Mod_Shutdown();
void DynOS_ReturnToMainMenu();
//
// Opt
//
s32 DynOS_Opt_GetValue(const String &aName);
void DynOS_Opt_SetValue(const String &aName, s32 aValue);
void DynOS_Opt_AddAction(const String &aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite);
void DynOS_Opt_Init();
void DynOS_Opt_InitVanilla(DynosOption *&aOptionsMenu);
void DynOS_Opt_Update(OSContPad *aPad);
bool DynOS_Opt_ControllerUpdate(DynosOption *aOpt, void *aData);
s32 DynOS_Opt_ControllerGetKeyPressed();
void DynOS_Opt_LoadConfig(DynosOption *aMenu);
void DynOS_Opt_SaveConfig(DynosOption *aMenu);
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
//
// Gfx
//
@ -826,22 +814,18 @@ s32 DynOS_String_Width(const u8 *aStr64);
// Levels
//
s32 DynOS_Level_GetCount();
const s32 *DynOS_Level_GetList();
s32 DynOS_Level_GetCourse(s32 aLevel);
void DynOS_Level_Init();
s8 DynOS_Level_GetCourse(s32 aLevel);
void DynOS_Level_Override(void* originalScript, void* newScript, s32 modIndex);
void DynOS_Level_Unoverride();
const void *DynOS_Level_GetScript(s32 aLevel);
s32 DynOS_Level_GetModIndex(s32 aLevel);
bool DynOS_Level_IsVanillaLevel(s32 aLevel);
const u8 *DynOS_Level_GetName(s32 aLevel, bool aDecaps, bool aAddCourseNumber);
const u8 *DynOS_Level_GetActName(s32 aLevel, s32 aAct, bool aDecaps, bool aAddStarNumber);
const u8 *DynOS_Level_GetAreaName(s32 aLevel, s32 aArea, bool aDecaps);
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId);
s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea);
s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea);
u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset);
void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize);
LvlCmd *DynOS_Level_CmdNext(LvlCmd *aCmd);
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
//
@ -854,8 +838,6 @@ bool DynOS_Warp_ToLevel(s32 aLevel, s32 aArea, s32 aAct);
bool DynOS_Warp_RestartLevel();
bool DynOS_Warp_ExitLevel(s32 aDelay);
bool DynOS_Warp_ToCastle(s32 aLevel);
void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex);
const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex);
//
// Builtin
@ -988,7 +970,6 @@ u32 DynOS_Model_GetIdFromAsset(void* asset);
u32 DynOS_Model_GetIdFromGraphNode(struct GraphNode* aNode);
void DynOS_Model_OverwriteSlot(u32 srcSlot, u32 dstSlot);
void DynOS_Model_ClearPool(enum ModelPool aModelPool);
void DynOS_Model_Update();
//
// Bin

View File

@ -10,7 +10,7 @@ extern "C" {
static inline bool ShouldUseF32Vtx(DataNode<Vtx>* aNode) {
for (u32 i = 0; i != aNode->mSize; ++i) {
for (u32 j = 0; j != 3; ++j) {
if (aNode->mData[i].n.ob[j] < -0x7FFF ||
if (aNode->mData[i].n.ob[j] < -0x7FFF ||
aNode->mData[i].n.ob[j] > +0x7FFF) {
return true;
}

View File

@ -14,14 +14,9 @@ void *dynos_update_cmd(void *cmd) {
}
void dynos_update_gfx() {
DynOS_Model_Update();
return DynOS_UpdateGfx();
}
void dynos_update_opt(void *pad) {
return DynOS_UpdateOpt(pad);
}
s32 dynos_tex_import(void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize) {
return DynOS_Tex_Import(output, ptr, tile, grapi, hashmap, pool, (u32 *) poolpos, (u32) poolsize);
}
@ -185,8 +180,8 @@ u64 dynos_level_cmd_get(void *cmd, u64 offset) {
return DynOS_Level_CmdGet(cmd, offset);
}
void dynos_level_cmd_next(void *cmd, u64 cmdsize) {
DynOS_Level_CmdNext(cmd, cmdsize);
void dynos_level_cmd_next(void *cmd) {
DynOS_Level_CmdNext((LvlCmd*) cmd);
}
void dynos_level_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *)) {

View File

@ -5,10 +5,6 @@ extern "C" {
#include "levels/scripts.h"
#include "pc/lua/utils/smlua_level_utils.h"
#ifdef VERSION_EU
#include "eu_translation.h"
#endif
}
//
@ -20,20 +16,6 @@ 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
//
@ -59,18 +41,18 @@ struct DynosLevelScript {
#define DYNOS_LEVEL_MOD_INDEX_VANILLA (-1)
static DynosLevelScript sDynosLevelScripts[LEVEL_COUNT] = { { NULL, DYNOS_LEVEL_MOD_INDEX_VANILLA } };
static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL };
extern void *gDynosLevelScriptsOriginal[LEVEL_COUNT];
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) {
LvlCmd *DynOS_Level_CmdNext(LvlCmd *aCmd) {
u64 aCmdSize = aCmd->mSize;
u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu)));
return (void *) (u64(aCmd) + _Offset);
return (LvlCmd*) (u64(aCmd) + _Offset);
}
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
@ -83,15 +65,7 @@ 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 {
if (sDynosScriptExecLevelTable) {
// JUMP_IF
if (aType == 0x0C) {
@ -105,21 +79,19 @@ static s32 DynOS_Level_PreprocessMasterScript(u8 aType, void *aCmd) {
if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum].mLevelScript) {
sDynosLevelScripts[sDynosLevelNum].mLevelScript = _Script;
sDynosLevelScripts[sDynosLevelNum].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
sDynosLevelScriptsOriginal[sDynosLevelNum] = _Script;
gDynosLevelScriptsOriginal[sDynosLevelNum] = _Script;
}
sDynosLevelNum = -1;
return 2;
}
// EXIT
if (aType == 0x02) {
return 3;
}
// SLEEP
if (aType == 0x03) {
// EXIT or SLEEP
if (aType == 0x02 || aType == 0x03) {
return 3;
}
} else if (aType == 0x06) { // JUMP_LINK
sDynosScriptExecLevelTable = true;
return 0;
}
return 0;
}
@ -184,8 +156,7 @@ static s32 DynOS_Level_PreprocessScript(u8 aType, void *aCmd) {
}
}
// SLEEP
// SLEEP_BEFORE_EXIT
// SLEEP or SLEEP_BEFORE_EXIT
else if (aType == 0x03 || aType == 0x04) {
return 3;
}
@ -194,30 +165,19 @@ static s32 DynOS_Level_PreprocessScript(u8 aType, void *aCmd) {
}
// Runs only once
static void DynOS_Level_Init() {
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) {
sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript = gDynosLevelScriptsOriginal[sDynosCurrentLevelNum];
sDynosLevelScripts[sDynosCurrentLevelNum].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
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;
}
@ -227,20 +187,8 @@ static void DynOS_Level_Init() {
// 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];
s8 DynOS_Level_GetCourse(s32 aLevel) {
return get_level_course_num(aLevel);
}
void DynOS_Level_Override(void* originalScript, void* newScript, s32 modIndex) {
@ -260,7 +208,7 @@ void DynOS_Level_Unoverride() {
for (s32 i = 0; i < LEVEL_COUNT; i++) {
sDynosCurrentLevelNum = i;
sDynosLevelWarps[i].Clear();
sDynosLevelScripts[i].mLevelScript = sDynosLevelScriptsOriginal[i];
sDynosLevelScripts[i].mLevelScript = gDynosLevelScriptsOriginal[i];
sDynosLevelScripts[i].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
DynOS_Level_ParseScript(sDynosLevelScripts[i].mLevelScript, DynOS_Level_PreprocessScript);
}
@ -289,205 +237,21 @@ s32 DynOS_Level_GetModIndex(s32 aLevel) {
}
bool DynOS_Level_IsVanillaLevel(s32 aLevel) {
if (aLevel >= 0 && aLevel < LEVEL_COUNT) {
return sDynosLevelScripts[aLevel].mLevelScript == sDynosLevelScriptsOriginal[aLevel];
DynOS_Level_Init();
if (aLevel >= LEVEL_MIN && aLevel < LEVEL_COUNT) {
return sDynosLevelScripts[aLevel].mLevelScript == gDynosLevelScriptsOriginal[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;
@ -512,7 +276,7 @@ static T StackPop(Stack& aStack) {
}
static LvlCmd *DynOS_Level_CmdExecute(Stack &aStack, LvlCmd *aCmd) {
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
StackPush(aStack, DynOS_Level_CmdNext(aCmd));
StackPush(aStack, aStack.mBaseIndex);
aStack.mBaseIndex = aStack.mTopIndex;
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 12);
@ -529,20 +293,12 @@ static LvlCmd *DynOS_Level_CmdExit(Stack &aStack, LvlCmd *aCmd) {
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));
StackPush(aStack, DynOS_Level_CmdNext(aCmd));
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 4);
}
@ -551,248 +307,40 @@ static LvlCmd *DynOS_Level_CmdReturn(Stack &aStack, UNUSED LvlCmd *aCmd) {
}
static LvlCmd *DynOS_Level_CmdJumpLinkPushArg(Stack &aStack, LvlCmd *aCmd) {
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
StackPush(aStack, DynOS_Level_CmdNext(aCmd));
StackPush(aStack, DynOS_Level_CmdGet(aCmd, 2));
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
return DynOS_Level_CmdNext(aCmd);
}
static LvlCmd *DynOS_Level_CmdJumpRepeat(Stack &aStack, LvlCmd *aCmd) {
aStack.mTopIndex -= 2;
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
return DynOS_Level_CmdNext(aCmd);
}
static LvlCmd *DynOS_Level_CmdLoopBegin(Stack &aStack, LvlCmd *aCmd) {
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
StackPush(aStack, DynOS_Level_CmdNext(aCmd));
StackPush(aStack, 0);
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
return DynOS_Level_CmdNext(aCmd);
}
static LvlCmd *DynOS_Level_CmdLoopUntil(Stack &aStack, LvlCmd *aCmd) {
aStack.mTopIndex -= 2;
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
return DynOS_Level_CmdNext(aCmd);
}
static LvlCmd *DynOS_Level_CmdJumpIf(Stack &aStack, LvlCmd *aCmd) {
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize)); /* Not an error, that's intentional */
StackPush(aStack, DynOS_Level_CmdNext(aCmd)); /* 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));
StackPush(aStack, DynOS_Level_CmdNext(aCmd));
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);
return DynOS_Level_CmdNext(aCmd);
}
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) {
@ -808,8 +356,6 @@ void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8,
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;
@ -819,64 +365,15 @@ void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8,
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;
default: _Cmd = DynOS_Level_CmdNext(_Cmd); break;
} break;
case 1:
_Cmd = (LvlCmd *) DynOS_Level_CmdNext(_Cmd, _Cmd->mSize);
_Cmd = DynOS_Level_CmdNext(_Cmd);
break;
case 2:
@ -900,10 +397,8 @@ s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
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;
}
if (_Warp.mArea == aArea && _Warp.mId == aWarpId) {
return (s16 *) &_Warp;
}
}
return NULL;
@ -912,10 +407,8 @@ s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
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;
}
if (_Warp.mArea == aArea && _Warp.mId == aWarpId) {
return (s16 *) &_Warp;
}
}
}
@ -924,7 +417,6 @@ s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
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) {

View File

@ -3,7 +3,6 @@ extern "C" {
#include "sm64.h"
#include "level_commands.h"
#include "game/level_update.h"
#include "game/options_menu.h"
#include "game/object_list_processor.h"
extern s16 gMenuMode;
extern s8 gDialogBoxState;
@ -17,38 +16,17 @@ extern void omm_opt_init();
//
void DynOS_ReturnToMainMenu() {
optmenu_toggle();
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
fade_into_special_warp(-2, 0);
}
//
// Init
//
DYNOS_AT_STARTUP void DynOS_Init() {
#ifdef OMM_DEFINES_H
omm_opt_init();
#endif
DynOS_Opt_Init();
}
//
// Update
//
static bool sDynosIsLevelEntry = false;
void DynOS_UpdateOpt(void *aPad) {
if (sDynosIsLevelEntry) {
DynOS_Warp_SetParam(gCurrLevelNum, -1);
sDynosIsLevelEntry = false;
}
DynOS_Opt_Update((OSContPad *) aPad);
gPrevFrameObjectCount = 0;
}
void *DynOS_SwapCmd(void *aCmd) {
return DynOS_Lvl_Override(aCmd);
}

View File

@ -43,7 +43,7 @@ void DynOS_Anim_Swap(void *aPtr) {
static Animation *pDefaultAnimation = NULL;
static Animation sGfxDataAnimation;
// Does the object has a model?
// Does the object have a model?
struct Object *_Object = (struct Object *) aPtr;
if (!_Object->header.gfx.sharedChild) {
return;

View File

@ -100,7 +100,7 @@ extern "C" {
} \
} \
return NULL;
#define MGR_FIND_DATA_FROM_TABLES(_DataTable, _DataTable2, _Cast) \
size_t _count = sizeof(_DataTable) / (2 * sizeof(_DataTable[0])); \
for (u32 _i = 0; _i < _count; _i++) { \
@ -183,6 +183,48 @@ static const void* sDynosBuiltinScriptPtrs[] = {
define_builtin(level_main_menu_entry_1),
};
#define define_level_original(lvl, script) (void*) script
void* gDynosLevelScriptsOriginal[LEVEL_COUNT] = {
define_level_original(0, NULL),
define_level_original(LEVEL_UNKNOWN_1, NULL),
define_level_original(LEVEL_UNKNOWN_2, NULL),
define_level_original(LEVEL_UNKNOWN_3, NULL),
define_level_original(LEVEL_BBH, level_bbh_entry),
define_level_original(LEVEL_CCM, level_ccm_entry),
define_level_original(LEVEL_CASTLE, level_castle_inside_entry),
define_level_original(LEVEL_HMC, level_hmc_entry),
define_level_original(LEVEL_SSL, level_ssl_entry),
define_level_original(LEVEL_BOB, level_bob_entry),
define_level_original(LEVEL_SL, level_sl_entry),
define_level_original(LEVEL_WDW, level_wdw_entry),
define_level_original(LEVEL_JRB, level_jrb_entry),
define_level_original(LEVEL_THI, level_thi_entry),
define_level_original(LEVEL_TTC, level_ttc_entry),
define_level_original(LEVEL_RR, level_rr_entry),
define_level_original(LEVEL_CASTLE_GROUNDS, level_castle_grounds_entry),
define_level_original(LEVEL_BITDW, level_bitdw_entry),
define_level_original(LEVEL_VCUTM, level_vcutm_entry),
define_level_original(LEVEL_BITFS, level_bitfs_entry),
define_level_original(LEVEL_SA, level_sa_entry),
define_level_original(LEVEL_BITS, level_bits_entry),
define_level_original(LEVEL_LLL, level_lll_entry),
define_level_original(LEVEL_DDD, level_ddd_entry),
define_level_original(LEVEL_WF, level_wf_entry),
define_level_original(LEVEL_ENDING, level_ending_entry),
define_level_original(LEVEL_CASTLE_COURTYARD, level_castle_courtyard_entry),
define_level_original(LEVEL_PSS, level_pss_entry),
define_level_original(LEVEL_COTMC, level_cotmc_entry),
define_level_original(LEVEL_TOTWC, level_totwc_entry),
define_level_original(LEVEL_BOWSER_1, level_bowser_1_entry),
define_level_original(LEVEL_WMOTR, level_wmotr_entry),
define_level_original(LEVEL_UNKNOWN_32, NULL),
define_level_original(LEVEL_BOWSER_2, level_bowser_2_entry),
define_level_original(LEVEL_BOWSER_3, level_bowser_3_entry),
define_level_original(LEVEL_UNKNOWN_35, NULL),
define_level_original(LEVEL_TTM, level_ttm_entry),
};
const void* DynOS_Builtin_ScriptPtr_GetFromName(const char* aDataName) {
MGR_FIND_DATA(sDynosBuiltinScriptPtrs, (const void*));
}
@ -1089,7 +1131,7 @@ static const void* sDynosBuiltinCols[] = {
define_builtin(wf_seg7_collision_trapezoid),
define_builtin(wf_seg7_collision_tumbling_bridge),
define_builtin(wmotr_seg7_collision),
// Actor Collisions
define_builtin(bbh_seg7_collision_coffin),
define_builtin(bbh_seg7_collision_haunted_bookshelf),
@ -1356,7 +1398,7 @@ static const void* sDynosBuiltinFuncs[] = {
define_builtin(geo_movtex_draw_water_regions_ext),
define_builtin(lvl_init_or_update),
define_builtin(geo_choose_area_ext),
// Behaviors
define_builtin(bhv_cap_switch_loop),
define_builtin(bhv_tiny_star_particles_init),
@ -1909,13 +1951,13 @@ static const void* sDynosBuiltinFuncs[] = {
define_builtin(bhv_dust_smoke_loop),
define_builtin(bhv_yoshi_loop),
define_builtin(bhv_volcano_trap_loop),
// mario_misc.h
define_builtin(bhv_toad_message_init),
define_builtin(bhv_toad_message_loop),
define_builtin(bhv_unlock_door_star_init),
define_builtin(bhv_unlock_door_star_loop),
// Other
define_builtin(load_object_collision_model),
define_builtin(obj_set_secondary_camera_focus),

View File

@ -56,7 +56,7 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLev
auto& _OverrideLevelScripts = DynosOverrideLevelScripts();
// make sure vanilla levels were parsed
DynOS_Level_GetCount();
DynOS_Level_Init();
// check for duplicates
for (s32 i = 0; i < _CustomLevelScripts.Count(); ++i) {
@ -121,7 +121,7 @@ const char* DynOS_Lvl_GetToken(u32 index) {
if (index >= gfxData->mLuaTokenList.Count()) {
return NULL;
}
return gfxData->mLuaTokenList[index].begin();
}

View File

@ -234,7 +234,3 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool) {
assetMap.clear();
}
void DynOS_Model_Update() {
}

View File

@ -1,749 +0,0 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/configfile.h"
#include "audio/external.h"
#include "game/game_init.h"
#include "pc/controller/controller_keyboard.h"
#ifdef BETTERCAMERA
#include "game/bettercamera.h"
#endif
}
//
// Data
//
static DynosOption *sPrevOpt = NULL;
static DynosOption *sDynosMenu = NULL;
static DynosOption *sOptionsMenu = NULL;
static DynosOption *sCurrentMenu = NULL;
static DynosOption *sCurrentOpt = NULL;
extern s32 sBindingState;
//
// Action list
//
typedef bool (*DynosActionFunction)(const char *);
struct DynosAction : NoCopy {
String mFuncName;
DynosActionFunction mAction;
};
STATIC_STORAGE(Array<DynosAction *>, DynosActions);
#define sDynosActions __DynosActions()
static DynosActionFunction DynOS_Opt_GetAction(const String& aFuncName) {
for (auto &_DynosAction : sDynosActions) {
if (_DynosAction->mFuncName == aFuncName) {
return _DynosAction->mAction;
}
}
return NULL;
}
void DynOS_Opt_AddAction(const String& aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite) {
for (auto &_DynosAction : sDynosActions) {
if (_DynosAction->mFuncName == aFuncName) {
if (aOverwrite) {
_DynosAction->mAction = aFuncPtr;
}
return;
}
}
DynosAction *_DynosAction = New<DynosAction>();
_DynosAction->mFuncName = aFuncName;
_DynosAction->mAction = aFuncPtr;
sDynosActions.Add(_DynosAction);
}
//
// Constructors
//
static DynosOption *DynOS_Opt_GetExistingOption(DynosOption *aOpt, const String &aName) {
while (aOpt) {
if (aOpt->mName == aName) {
return aOpt;
}
if (aOpt->mType == DOPT_SUBMENU) {
DynosOption *_Opt = DynOS_Opt_GetExistingOption(aOpt->mSubMenu.mChild, aName);
if (_Opt) {
return _Opt;
}
}
aOpt = aOpt->mNext;
}
return NULL;
}
static DynosOption *DynOS_Opt_NewOption(const String &aName, const String &aConfigName, const String &aLabel, const String &aTitle) {
// Check if the option already exists
static DynosOption sDummyOpt;
if (DynOS_Opt_GetExistingOption(sDynosMenu, aName)) {
return &sDummyOpt;
}
// Create a new option
DynosOption *_Opt = New<DynosOption>();
_Opt->mName = aName;
_Opt->mConfigName = aConfigName;
_Opt->mLabel = { aLabel, NULL };
_Opt->mTitle = { aTitle, NULL };
_Opt->mDynos = true;
if (sPrevOpt == NULL) { // The very first option
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = NULL;
sDynosMenu = _Opt;
} else {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt;
sPrevOpt->mSubMenu.mChild = _Opt;
sPrevOpt->mSubMenu.mEmpty = false;
} else {
_Opt->mPrev = sPrevOpt;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt->mParent;
sPrevOpt->mNext = _Opt;
}
}
sPrevOpt = _Opt;
return _Opt;
}
static void DynOS_Opt_EndSubMenu() {
if (sPrevOpt && sPrevOpt->mParent) {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
sPrevOpt->mSubMenu.mEmpty = false;
} else {
sPrevOpt = sPrevOpt->mParent;
}
}
}
static void DynOS_Opt_CreateSubMenu(const String &aName, const String &aLabel, const String &aTitle) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aTitle);
_Opt->mType = DOPT_SUBMENU;
_Opt->mSubMenu.mChild = NULL;
_Opt->mSubMenu.mEmpty = true;
}
static void DynOS_Opt_CreateToggle(const String &aName, const String &aConfigName, const String &aLabel, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_TOGGLE;
_Opt->mToggle.mTog = New<bool>();
*_Opt->mToggle.mTog = (bool) aValue;
}
static void DynOS_Opt_CreateScroll(const String &aName, const String &aConfigName, const String &aLabel, s32 aMin, s32 aMax, s32 aStep, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_SCROLL;
_Opt->mScroll.mMin = aMin;
_Opt->mScroll.mMax = aMax;
_Opt->mScroll.mStep = aStep;
_Opt->mScroll.mValue = New<s32>();
*_Opt->mScroll.mValue = aValue;
}
static void DynOS_Opt_CreateChoice(const String &aName, const String &aConfigName, const String &aLabel, const Array<String>& aChoices, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_CHOICE;
_Opt->mChoice.mIndex = New<s32>();
*_Opt->mChoice.mIndex = aValue;
for (const auto &_Choice : aChoices) {
_Opt->mChoice.mChoices.Add({ _Choice, NULL });
}
}
static void DynOS_Opt_CreateButton(const String &aName, const String &aLabel, const String& aFuncName) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aLabel);
_Opt->mType = DOPT_BUTTON;
_Opt->mButton.mFuncName = aFuncName;
}
static void DynOS_Opt_CreateBind(const String &aName, const String &aConfigName, const String &aLabel, u32 aMask, u32 aBind0, u32 aBind1, u32 aBind2) {
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
_Opt->mType = DOPT_BIND;
_Opt->mBind.mMask = aMask;
_Opt->mBind.mBinds = New<u32>(3);
_Opt->mBind.mBinds[0] = aBind0;
_Opt->mBind.mBinds[1] = aBind1;
_Opt->mBind.mBinds[2] = aBind2;
_Opt->mBind.mIndex = 0;
}
//
// Loop through DynosOptions
//
DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData) {
while (aOpt) {
if (aFunc(aOpt, aData)) {
return aOpt;
} else if (aOpt->mType == DOPT_SUBMENU) {
DynosOption *_Opt = DynOS_Opt_Loop(aOpt->mSubMenu.mChild, aFunc, aData);
if (_Opt) {
return _Opt;
}
}
aOpt = aOpt->mNext;
}
return NULL;
}
//
// Get/Set values
//
static bool DynOS_Opt_Get(DynosOption *aOpt, void *aData) {
return aOpt->mName == (const char *) aData;
}
s32 DynOS_Opt_GetValue(const String &aName) {
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
if (_Opt) {
switch (_Opt->mType) {
case DOPT_TOGGLE: return *_Opt->mToggle.mTog;
case DOPT_CHOICE: return *_Opt->mChoice.mIndex;
case DOPT_CHOICELEVEL: return *_Opt->mChoice.mIndex;
case DOPT_CHOICEAREA: return *_Opt->mChoice.mIndex;
case DOPT_CHOICESTAR: return *_Opt->mChoice.mIndex;
case DOPT_CHOICEPARAM: return *_Opt->mChoice.mIndex;
case DOPT_SCROLL: return *_Opt->mScroll.mValue;
default: break;
}
}
return 0;
}
void DynOS_Opt_SetValue(const String &aName, s32 aValue) {
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
if (_Opt) {
switch (_Opt->mType) {
case DOPT_TOGGLE: *_Opt->mToggle.mTog = aValue; break;
case DOPT_CHOICE: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICELEVEL: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICEAREA: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICESTAR: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_CHOICEPARAM: *_Opt->mChoice.mIndex = aValue; break;
case DOPT_SCROLL: *_Opt->mScroll.mValue = aValue; break;
default: break;
}
}
}
//
// Processing
//
#define SOUND_DYNOS_SAVED (SOUND_MENU_MARIO_CASTLE_WARP2 | (0xFF << 8))
#define SOUND_DYNOS_SELECT (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
#define SOUND_DYNOS_OK (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
#define SOUND_DYNOS_CANCEL (SOUND_MENU_CAMERA_BUZZ | (0xFC << 8))
enum {
INPUT_LEFT,
INPUT_RIGHT,
INPUT_A,
INPUT_Z
};
enum {
RESULT_NONE,
RESULT_OK,
RESULT_CANCEL
};
static s32 DynOS_Opt_ProcessInput(DynosOption *aOpt, s32 input) {
switch (aOpt->mType) {
case DOPT_TOGGLE:
if (input == INPUT_LEFT) {
*aOpt->mToggle.mTog = false;
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
*aOpt->mToggle.mTog = true;
return RESULT_OK;
}
if (input == INPUT_A) {
*aOpt->mToggle.mTog = !(*aOpt->mToggle.mTog);
return RESULT_OK;
}
break;
case DOPT_CHOICE:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + aOpt->mChoice.mChoices.Count() - 1) % (aOpt->mChoice.mChoices.Count());
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (aOpt->mChoice.mChoices.Count());
return RESULT_OK;
}
break;
case DOPT_CHOICELEVEL:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + DynOS_Level_GetCount() - 1) % (DynOS_Level_GetCount());
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (DynOS_Level_GetCount());
return RESULT_OK;
}
break;
case DOPT_CHOICEAREA:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 3) % (4);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (4);
return RESULT_OK;
}
break;
case DOPT_CHOICESTAR:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 5) % (6);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (6);
return RESULT_OK;
}
break;
case DOPT_CHOICEPARAM:
if (input == INPUT_LEFT) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 4) % (5);
return RESULT_OK;
}
if (input == INPUT_RIGHT || input == INPUT_A) {
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (5);
return RESULT_OK;
}
break;
case DOPT_SCROLL:
if (input == INPUT_LEFT) {
*aOpt->mScroll.mValue = MAX(aOpt->mScroll.mMin, *aOpt->mScroll.mValue - aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
*aOpt->mScroll.mValue = MIN(aOpt->mScroll.mMax, *aOpt->mScroll.mValue + aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
return RESULT_OK;
}
break;
case DOPT_BIND:
if (input == INPUT_LEFT) {
aOpt->mBind.mIndex = MAX(0, aOpt->mBind.mIndex - 1);
return RESULT_OK;
}
if (input == INPUT_RIGHT) {
aOpt->mBind.mIndex = MIN(2, aOpt->mBind.mIndex + 1);
return RESULT_OK;
}
if (input == INPUT_Z) {
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
return RESULT_OK;
}
if (input == INPUT_A) {
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
sBindingState = 1;
controller_get_raw_key();
return RESULT_OK;
}
break;
case DOPT_BUTTON:
if (input == INPUT_A) {
DynosActionFunction _Action = DynOS_Opt_GetAction(aOpt->mButton.mFuncName);
if (_Action != NULL && _Action(aOpt->mName.begin())) {
return RESULT_OK;
}
return RESULT_CANCEL;
}
break;
case DOPT_SUBMENU:
if (input == INPUT_A) {
if (aOpt->mSubMenu.mChild != NULL) {
sCurrentOpt = aOpt->mSubMenu.mChild;
return RESULT_OK;
}
return RESULT_CANCEL;
}
break;
}
return RESULT_NONE;
}
static void DynOS_Opt_Open(DynosOption *aMenu) {
play_sound(SOUND_DYNOS_SELECT, gGlobalSoundSource);
sCurrentMenu = aMenu;
sCurrentOpt = aMenu;
}
static void DynOS_Opt_Close(bool aPlaySavedSfx) {
if (sCurrentMenu != NULL) {
if (aPlaySavedSfx) {
play_sound(SOUND_DYNOS_SAVED, gGlobalSoundSource);
}
#ifdef BETTERCAMERA
newcam_init_settings();
#endif
controller_reconfigure();
configfile_save(configfile_name());
DynOS_Opt_SaveConfig(sDynosMenu);
sCurrentMenu = NULL;
}
}
static void DynOS_Opt_ProcessInputs() {
static s32 sStickTimer = 0;
static bool sPrevStick = 0;
// Stick values
f32 _StickX = gPlayer1Controller->stickX;
f32 _StickY = gPlayer1Controller->stickY;
if (absx(_StickX) > 60 || absx(_StickY) > 60) {
if (sStickTimer == 0) {
sStickTimer = (sPrevStick ? 2 : 9);
} else {
_StickX = 0;
_StickY = 0;
sStickTimer--;
}
sPrevStick = true;
} else {
sStickTimer = 0;
sPrevStick = false;
}
// Key binding
if (sBindingState != 0) {
u32 _Key = (sCurrentOpt->mDynos ? (u32) DynOS_Opt_ControllerGetKeyPressed() : controller_get_raw_key());
if (_Key != VK_INVALID) {
play_sound(SOUND_DYNOS_SELECT, gGlobalSoundSource);
sCurrentOpt->mBind.mBinds[sCurrentOpt->mBind.mIndex] = _Key;
sBindingState = false;
}
return;
}
if (sCurrentMenu != NULL) {
// Up
if (_StickY > +60) {
if (sCurrentOpt->mPrev != NULL) {
sCurrentOpt = sCurrentOpt->mPrev;
} else {
while (sCurrentOpt->mNext) sCurrentOpt = sCurrentOpt->mNext;
}
play_sound(SOUND_DYNOS_SELECT, gGlobalSoundSource);
return;
}
// Down
if (_StickY < -60) {
if (sCurrentOpt->mNext != NULL) {
sCurrentOpt = sCurrentOpt->mNext;
} else {
while (sCurrentOpt->mPrev) sCurrentOpt = sCurrentOpt->mPrev;
}
play_sound(SOUND_DYNOS_SELECT, gGlobalSoundSource);
return;
}
// Left
if (_StickX < -60) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_LEFT)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gGlobalSoundSource); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gGlobalSoundSource); break;
case RESULT_NONE: break;
}
return;
}
// Right
if (_StickX > +60) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_RIGHT)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gGlobalSoundSource); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gGlobalSoundSource); break;
case RESULT_NONE: break;
}
return;
}
// A
if (gPlayer1Controller->buttonPressed & A_BUTTON) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_A)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gGlobalSoundSource); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gGlobalSoundSource); break;
case RESULT_NONE: break;
}
return;
}
// B
if (gPlayer1Controller->buttonPressed & B_BUTTON) {
if (sCurrentOpt->mParent != NULL) {
sCurrentOpt = sCurrentOpt->mParent;
play_sound(SOUND_DYNOS_SELECT, gGlobalSoundSource);
} else {
DynOS_Opt_Close(true);
}
return;
}
// Z
if (gPlayer1Controller->buttonPressed & Z_TRIG) {
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_Z)) {
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gGlobalSoundSource); break;
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gGlobalSoundSource); break;
case RESULT_NONE:
if (sCurrentMenu == sDynosMenu) {
DynOS_Opt_Close(true);
} else {
DynOS_Opt_Open(sDynosMenu);
} break;
}
return;
}
// R
if (gPlayer1Controller->buttonPressed & R_TRIG) {
if (sCurrentMenu == sOptionsMenu) {
DynOS_Opt_Close(true);
} else {
DynOS_Opt_Open(sOptionsMenu);
}
return;
}
// Start
if (gPlayer1Controller->buttonPressed & START_BUTTON) {
DynOS_Opt_Close(true);
return;
}
} else if (gPlayer1Controller->buttonPressed & R_TRIG) {
DynOS_Opt_Open(sOptionsMenu);
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
DynOS_Opt_Open(sDynosMenu);
}
}
//
// Init
//
static void DynOS_Opt_CreateWarpToLevelSubMenu() {
DynOS_Opt_CreateSubMenu("dynos_warp_to_level_submenu", "Warp to Level", "WARP TO LEUEL");
// Level select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_level", "", "Level Select", "");
aOpt->mType = DOPT_CHOICELEVEL;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Area select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_area", "", "Area Select", "");
aOpt->mType = DOPT_CHOICEAREA;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Star select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_act", "", "Star Select", "");
aOpt->mType = DOPT_CHOICESTAR;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
// Param select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_param", "", "Param Select", "");
aOpt->mType = DOPT_CHOICEPARAM;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
DynOS_Opt_CreateButton("dynos_warp_to_level", "Warp", "DynOS_Opt_WarpToLevel");
DynOS_Opt_EndSubMenu();
}
static void DynOS_Opt_CreateWarpToCastleSubMenu() {
DynOS_Opt_CreateSubMenu("dynos_warp_to_castle_submenu", "Warp to Castle", "WARP TO CASTLE");
// Level select
{
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_castle", "", "Level Exit", "");
aOpt->mType = DOPT_CHOICELEVEL;
aOpt->mChoice.mIndex = New<s32>();
*aOpt->mChoice.mIndex = 0;
}
DynOS_Opt_CreateButton("dynos_warp_to_castle", "Warp", "DynOS_Opt_WarpToCastle");
DynOS_Opt_EndSubMenu();
}
static u32 DynOS_Opt_GetHash(const String& aStr) {
u32 _Hash = 5381u;
for (char c : aStr) { _Hash += c + (_Hash << 5); }
return _Hash;
}
static void DynOS_Opt_CreateModelPacksSubMenu() {
/*Array<String> _Packs = DynOS_Gfx_Init();
if (_Packs.Count() == 0) {
return;
}
DynOS_Opt_CreateSubMenu("dynos_model_loader_submenu", "Model Packs", "MODEL PACKS");
for (s32 i = 0; i != _Packs.Count(); ++i) {
DynOS_Opt_CreateToggle(String("dynos_pack_%d", i), String("dynos_pack_%08X", DynOS_Opt_GetHash(_Packs[i])), _Packs[i], false);
}
DynOS_Opt_CreateButton("dynos_packs_disable_all", "Disable all packs", "DynOS_Opt_DisableAllPacks");
DynOS_Opt_EndSubMenu();*/
}
void DynOS_Opt_Init() {
#ifdef COOP
#else
// Convert options menu
DynOS_Opt_InitVanilla(sOptionsMenu);
// Warp to level
DynOS_Opt_CreateWarpToLevelSubMenu();
// Warp to castle
DynOS_Opt_CreateWarpToCastleSubMenu();
// Restart level
DynOS_Opt_CreateButton("dynos_restart_level", "Restart Level", "DynOS_Opt_RestartLevel");
// Exit level
DynOS_Opt_CreateButton("dynos_exit_level", "Exit Level", "DynOS_Opt_ExitLevel");
// Return to main menu
DynOS_Opt_CreateButton("dynos_return_to_main_menu", "Return to Main Menu", "DynOS_Opt_ReturnToMainMenu");
// Model loader
DynOS_Opt_CreateModelPacksSubMenu();
// Init config
DynOS_Opt_LoadConfig(sDynosMenu);
#endif
}
//
// Update
//
void DynOS_Opt_Update(OSContPad *aPad) {
DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_ControllerUpdate, (void *) aPad);
#ifndef COOP
if (DynOS_IsTransitionActive()) {
aPad->button = 0;
aPad->stick_x = 0;
aPad->stick_y = 0;
aPad->ext_stick_x = 0;
aPad->ext_stick_y = 0;
}
#endif
}
//
// Hijack
// This is C code
//
extern "C" {
u8 optmenu_open = 0;
void optmenu_toggle(void) {
DynOS_Opt_Close(false);
optmenu_open = 0;
}
void optmenu_draw(void) {
DynOS_Opt_DrawMenu(sCurrentOpt, sCurrentMenu, sOptionsMenu, sDynosMenu);
}
void optmenu_draw_prompt(void) {
DynOS_Opt_DrawPrompt(sCurrentMenu, sOptionsMenu, sDynosMenu);
DynOS_Opt_ProcessInputs();
optmenu_open = (sCurrentMenu != NULL);
}
void optmenu_check_buttons(void) {
}
}
//
// Built-in options
//
#define DYNOS_DEFINE_ACTION(func) \
DYNOS_AT_STARTUP static void DynOS_Opt_AddAction_##func() { \
DynOS_Opt_AddAction(#func, func, false); \
}
#ifndef COOP
static bool DynOS_Opt_ReturnToMainMenu(UNUSED const char *optName) {
DynOS_ReturnToMainMenu();
return true;
}
DYNOS_DEFINE_ACTION(DynOS_Opt_ReturnToMainMenu);
static bool DynOS_Opt_WarpToLevel(UNUSED const char *optName) {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
s32 _Area = DynOS_Opt_GetValue("dynos_warp_area") + 1;
s32 _Act = DynOS_Opt_GetValue("dynos_warp_act") + 1;
return DynOS_Warp_ToLevel(_Level, _Area, _Act);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToLevel);
static bool DynOS_Opt_WarpToCastle(UNUSED const char *optName) {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_castle")];
return DynOS_Warp_ToCastle(_Level);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToCastle);
static bool DynOS_Opt_RestartLevel(UNUSED const char *optName) {
return DynOS_Warp_RestartLevel();
}
DYNOS_DEFINE_ACTION(DynOS_Opt_RestartLevel);
static bool DynOS_Opt_ExitLevel(UNUSED const char *optName) {
return DynOS_Warp_ExitLevel(30);
}
DYNOS_DEFINE_ACTION(DynOS_Opt_ExitLevel);
static bool DynOS_Opt_DisableAllPacks(UNUSED const char *optName) {
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
DynOS_Opt_SetValue(String("dynos_pack_%d", i), false);
}
return true;
}
DYNOS_DEFINE_ACTION(DynOS_Opt_DisableAllPacks);
#endif
#undef DYNOS_DEFINE_ACTION

View File

@ -1,67 +0,0 @@
#include "dynos.cpp.h"
extern DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData);
static bool DynOS_Opt_ReadConfig(DynosOption *aOpt, void *aData) {
return (aOpt->mConfigName == (const char *) aData);
}
void DynOS_Opt_LoadConfig(DynosOption *aMenu) {
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
FILE *_File = fopen(_Filename.c_str(), "r");
if (_File) {
char _Buffer[1024];
while (fgets(_Buffer, 1024, _File)) {
// Option strings
char *_NameBegin = _Buffer;
char *_DataBegin = strchr(_NameBegin, '=');
if (_NameBegin && _DataBegin) {
*(_DataBegin++) = 0;
// Option name
String _OptName = String(_NameBegin);
DynosOption *_Opt = DynOS_Opt_Loop(aMenu, DynOS_Opt_ReadConfig, (void *) _OptName.begin());
if (_Opt) {
// Option values
switch (_Opt->mType) {
case DOPT_TOGGLE: {
unsigned char boolValue = 0;
sscanf(_DataBegin, "%hhu\n", &boolValue);
_Opt->mToggle.mTog[0] = boolValue;
break;
}
case DOPT_CHOICE: sscanf(_DataBegin, "%d\n", &_Opt->mChoice.mIndex[0]); break;
case DOPT_SCROLL: sscanf(_DataBegin, "%d\n", &_Opt->mScroll.mValue[0]); break;
case DOPT_BIND: sscanf(_DataBegin, "%04X;%04X;%04X\n", &_Opt->mBind.mBinds[0], &_Opt->mBind.mBinds[1], &_Opt->mBind.mBinds[2]); break;
}
}
}
}
fclose(_File);
}
}
static bool DynOS_Opt_WriteConfig(DynosOption *aOpt, void *aData) {
if (aOpt->mConfigName.Length() != 0 &&
aOpt->mConfigName != "null" &&
aOpt->mConfigName != "NULL") {
switch (aOpt->mType) {
case DOPT_TOGGLE: fprintf((FILE *) aData, "%s=%hhu\n", aOpt->mConfigName.begin(), aOpt->mToggle.mTog[0]); break;
case DOPT_CHOICE: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mChoice.mIndex[0]); break;
case DOPT_SCROLL: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mScroll.mValue[0]); break;
case DOPT_BIND: fprintf((FILE *) aData, "%s=%04X;%04X;%04X\n", aOpt->mConfigName.begin(), aOpt->mBind.mBinds[0], aOpt->mBind.mBinds[1], aOpt->mBind.mBinds[2]); break;
}
}
return false;
}
void DynOS_Opt_SaveConfig(DynosOption *aMenu) {
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
FILE *_File = fopen(_Filename.c_str(), "w");
if (_File) {
DynOS_Opt_Loop(aMenu, DynOS_Opt_WriteConfig, (void *) _File);
fclose(_File);
}
}

View File

@ -1,75 +0,0 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/controller/controller_api.h"
}
static bool DynOS_Opt_ControllerIsKeyDown(s32 aCont, s32 aKey) {
#ifdef HAVE_SDL2
// Keyboard
if (aCont == 0 && aKey >= 0 && aKey < SDL_NUM_SCANCODES) {
return SDL_GetKeyboardState(NULL)[aKey];
}
// Game Controller
else if (aKey >= 0x1000) {
// Button
s32 _Button = (aKey - 0x1000);
if (_Button < SDL_CONTROLLER_BUTTON_MAX) {
return SDL_GameControllerGetButton(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerButton(_Button));
}
// Axis
s32 _Axis = (aKey - 0x1000 - SDL_CONTROLLER_BUTTON_MAX);
if (_Axis < SDL_CONTROLLER_AXIS_MAX * 2) {
s32 _AxisValue = SDL_GameControllerGetAxis(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerAxis(_Axis / 2));
if (_Axis & 1) return (_AxisValue < (SHRT_MIN / 2));
else return (_AxisValue > (SHRT_MAX / 2));
}
}
// Invalid
#endif
return false;
}
#define MAX_CONTS 8
bool DynOS_Opt_ControllerUpdate(DynosOption *aOpt, void *aData) {
#ifdef HAVE_SDL2
if (aOpt->mType == DOPT_BIND) {
OSContPad *pad = (OSContPad *) aData;
for (s32 _Cont = 0; _Cont < MAX_CONTS; ++_Cont)
for (s32 _Bind = 0; _Bind < 3; ++_Bind) {
pad->button |= aOpt->mBind.mMask * DynOS_Opt_ControllerIsKeyDown(_Cont, aOpt->mBind.mBinds[_Bind]);
}
}
#endif
return false;
}
#define MAX_GKEYS (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_MAX * 2)
s32 sBindingState = 0; // 0 = No bind, 1 = Wait for all keys released, 2 = Return first pressed key
s32 DynOS_Opt_ControllerGetKeyPressed() {
#ifdef HAVE_SDL2
// Keyboard
for (s32 _Key = 0; _Key < SDL_NUM_SCANCODES; ++_Key) {
if (DynOS_Opt_ControllerIsKeyDown(0, _Key)) {
if (sBindingState == 1) return VK_INVALID;
return _Key;
}
}
// Game Controller
for (s32 _Cont = 1; _Cont < MAX_CONTS; ++_Cont)
for (s32 _Key = 0; _Key < MAX_GKEYS; ++_Key) {
if (DynOS_Opt_ControllerIsKeyDown(_Cont, _Key + 0x1000)) {
if (sBindingState == 1) return VK_INVALID;
return _Key + 0x1000;
}
}
// No key
sBindingState = 2;
#endif
return VK_INVALID;
}

View File

@ -1,309 +0,0 @@
#include "dynos.cpp.h"
extern "C" {
#include "course_table.h"
#include "game/game_init.h"
#include "game/ingame_menu.h"
#include "game/segment2.h"
#include "pc/controller/controller_api.h"
#include "gfx_dimensions.h"
}
extern s32 sBindingState;
#define DYNOS_TEXT_DYNOS_MENU { "DYNOS MENU", NULL }
#define DYNOS_TEXT_A { "([A]) >", NULL }
#define DYNOS_TEXT_OPEN_LEFT { "[Z] DynOS", NULL }
#define DYNOS_TEXT_CLOSE_LEFT { "[Z] Return", NULL }
#define DYNOS_TEXT_OPTIONS_MENU { "OPTIONS", NULL }
#define DYNOS_TEXT_DISABLED { "Disabled", NULL }
#define DYNOS_TEXT_ENABLED { "Enabled", NULL }
#define DYNOS_TEXT_NONE { "NONE", NULL }
#define DYNOS_TEXT_DOT_DOT_DOT { "...", NULL }
#define DYNOS_TEXT_OPEN_RIGHT { "[R] Options", NULL }
#define DYNOS_TEXT_CLOSE_RIGHT { "[R] Return", NULL }
static void RenderString(const u8 *aStr64, s32 aX, s32 aY) {
create_dl_translation_matrix(MENU_MTX_PUSH, aX, aY, 0);
for (; *aStr64 != DIALOG_CHAR_TERMINATOR; ++aStr64) {
if (*aStr64 != DIALOG_CHAR_SPACE) {
void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
void *packedTexture = segmented_to_virtual(fontLUT[*aStr64]);
gDPPipeSync(gDisplayListHead++);
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
}
create_dl_translation_matrix(MENU_MTX_NOPUSH, DynOS_String_WidthChar64(*aStr64), 0, 0);
}
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
static void PrintString(const Label& aLabel, s32 aX, s32 aY, u32 aFrontColorRGBA, u32 aBackColorRGBA, bool aAlignLeft) {
const u8 *_Str64 = (aLabel.second ? aLabel.second : DynOS_String_Convert(aLabel.first.begin(), false));
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
if ((aBackColorRGBA & 0xFF) != 0) {
gDPSetEnvColor(gDisplayListHead++, ((aBackColorRGBA >> 24) & 0xFF), ((aBackColorRGBA >> 16) & 0xFF), ((aBackColorRGBA >> 8) & 0xFF), ((aBackColorRGBA >> 0) & 0xFF));
if (aAlignLeft) {
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX) + 1, aY - 1);
} else {
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64) - 1), aY - 1);
}
}
if ((aFrontColorRGBA & 0xFF) != 0) {
gDPSetEnvColor(gDisplayListHead++, ((aFrontColorRGBA >> 24) & 0xFF), ((aFrontColorRGBA >> 16) & 0xFF), ((aFrontColorRGBA >> 8) & 0xFF), ((aFrontColorRGBA >> 0) & 0xFF));
if (aAlignLeft) {
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY);
} else {
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64)), aY);
}
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
static void PrintBox(s32 aX, s32 aY, s32 aWidth, s32 aHeight, u32 aColorRGBA, bool aAlignLeft) {
if ((aColorRGBA & 0xFF) != 0) {
Mtx *_Matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
if (!_Matrix) return;
if (aAlignLeft) {
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY + aHeight, 0);
} else {
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + aWidth), aY + aHeight, 0);
}
guScale(_Matrix, (f32) aWidth / 130.f, (f32) aHeight / 80.f, 1.f);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(_Matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
gDPSetEnvColor(gDisplayListHead++, ((aColorRGBA >> 24) & 0xFF), ((aColorRGBA >> 16) & 0xFF), ((aColorRGBA >> 8) & 0xFF), ((aColorRGBA >> 0) & 0xFF));
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
}
}
static const char *IntToString(const char *fmt, s32 x) {
static char sBuffer[16];
snprintf(sBuffer, 16, fmt, x);
return sBuffer;
}
#define get_label(opt) (opt->mLabel)
#define get_title(opt) (opt->mTitle)
#define get_choice(opt) (opt->mChoice.mChoices[*opt->mChoice.mIndex])
#define get_dec_number(n) { "", DynOS_String_Convert(IntToString("%d", n), false) }
#define get_hex_number(n) { "", DynOS_String_Convert(IntToString("%04X", n), false) }
#define get_level(opt) { "", DynOS_Level_GetName(DynOS_Level_GetList()[*opt->mChoice.mIndex], true, true) }
#define get_star(opt) { "", DynOS_Level_GetActName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex + 1, true, true) }
#define get_param(opt) { DynOS_Warp_GetParamName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex), NULL }
static s32 GetCurrentOptionCount(DynosOption *aCurrentOpt) {
s32 _Count = 0;
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; }
while (aCurrentOpt) { aCurrentOpt = aCurrentOpt->mNext; _Count++; }
return _Count;
}
static s32 GetCurrentOptionIndex(DynosOption *aCurrentOpt) {
s32 _Index = 0;
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; _Index++; }
return _Index;
}
#define PREV(opt) (opt == NULL ? NULL : opt->mPrev)
#define NEXT(opt) (opt == NULL ? NULL : opt->mNext)
static DynosOption **GetCurrentOptions(DynosOption *aCurrentOpt) {
static DynosOption *sOptionList[13];
sOptionList[6] = aCurrentOpt;
sOptionList[5] = PREV(sOptionList[6]);
sOptionList[4] = PREV(sOptionList[5]);
sOptionList[3] = PREV(sOptionList[4]);
sOptionList[2] = PREV(sOptionList[3]);
sOptionList[1] = PREV(sOptionList[2]);
sOptionList[0] = PREV(sOptionList[1]);
sOptionList[7] = NEXT(sOptionList[6]);
sOptionList[8] = NEXT(sOptionList[7]);
sOptionList[9] = NEXT(sOptionList[8]);
sOptionList[10] = NEXT(sOptionList[9]);
sOptionList[11] = NEXT(sOptionList[10]);
sOptionList[12] = NEXT(sOptionList[11]);
s32 _StartIndex = 12, _EndIndex = 0;
for (s32 i = 0; i != 13; ++i) {
if (sOptionList[i] != NULL) {
_StartIndex = MIN(_StartIndex, i);
_EndIndex = MAX(_EndIndex, i);
}
}
if (_EndIndex - _StartIndex < 7) {
return &sOptionList[_StartIndex];
}
if (_EndIndex <= 9) {
return &sOptionList[_EndIndex - 6];
}
if (_StartIndex >= 3) {
return &sOptionList[_StartIndex];
}
return &sOptionList[3];
}
#undef PREV
#undef NEXT
#define COLOR_WHITE 0xFFFFFFFF
#define COLOR_BLACK 0x000000FF
#define COLOR_GRAY 0xA0A0A0FF
#define COLOR_DARK_GRAY 0x808080FF
#define COLOR_SELECT 0x80E0FFFF
#define COLOR_SELECT_BOX 0x00FFFF20
#define COLOR_ENABLED 0x20E020FF
#define COLOR_DISABLED 0xFF2020FF
#define OFFSET_FROM_LEFT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
#define OFFSET_FROM_RIGHT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
#define SCROLL_BAR_SIZE ((s32) (45.f * GFX_DIMENSIONS_ASPECT_RATIO))
static void DynOS_Opt_DrawOption(DynosOption *aOpt, DynosOption *aCurrentOpt, s32 aY) {
if (aOpt == NULL) {
return;
}
// Selected box
if (aOpt == aCurrentOpt) {
u8 _Alpha = (u8) ((coss(gGlobalTimer * 0x800) + 1.f) * 0x20);
PrintBox(OFFSET_FROM_LEFT_EDGE - 4, aY - 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(OFFSET_FROM_RIGHT_EDGE) - GFX_DIMENSIONS_FROM_LEFT_EDGE(OFFSET_FROM_LEFT_EDGE) + 8, 20, COLOR_SELECT_BOX + _Alpha, 1);
}
// Label
if (aOpt == aCurrentOpt) {
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 1);
} else {
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_WHITE, COLOR_BLACK, 1);
}
// Values
switch (aOpt->mType) {
case DOPT_TOGGLE: {
if (*aOpt->mToggle.mTog) {
PrintString(DYNOS_TEXT_ENABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_ENABLED, COLOR_BLACK, 0);
} else {
PrintString(DYNOS_TEXT_DISABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_DISABLED, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICE: {
PrintString(get_choice(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_CHOICELEVEL: {
PrintString(get_level(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_CHOICEAREA: {
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
s32 _Area = *aOpt->mChoice.mIndex + 1;
const u8 *_Name = DynOS_Level_GetAreaName(_Level, _Area, true);
if (DynOS_Level_GetWarpEntry(_Level, _Area)) {
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} else {
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_GRAY, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICESTAR: {
s32 _Course = DynOS_Level_GetCourse(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")]);
if (_Course >= COURSE_MIN && _Course <= COURSE_STAGES_MAX) {
PrintString(get_star(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
}
} break;
case DOPT_CHOICEPARAM: {
PrintString(get_param(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
} break;
case DOPT_SCROLL: {
s32 _Width = (s32) (SCROLL_BAR_SIZE * (f32) (*aOpt->mScroll.mValue - aOpt->mScroll.mMin) / (f32) (aOpt->mScroll.mMax - aOpt->mScroll.mMin));
PrintString(get_dec_number(*aOpt->mScroll.mValue), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE + 28, aY + 4, SCROLL_BAR_SIZE + 2, 8, COLOR_DARK_GRAY, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE + 29 + SCROLL_BAR_SIZE - _Width, aY + 5, _Width, 6, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, 0);
} break;
case DOPT_BIND: {
for (s32 i = 0; i != 3; ++i) {
u32 _Bind = aOpt->mBind.mBinds[i];
if (aOpt == aCurrentOpt && i == aOpt->mBind.mIndex) {
if (sBindingState != 0) {
PrintString(DYNOS_TEXT_DOT_DOT_DOT, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
} else if (_Bind == VK_INVALID) {
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
} else {
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
}
} else {
if (_Bind == VK_INVALID) {
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_GRAY, COLOR_BLACK, 0);
} else {
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_WHITE, COLOR_BLACK, 0);
}
}
}
} break;
case DOPT_BUTTON: {
} break;
case DOPT_SUBMENU: {
if (aOpt == aCurrentOpt) {
PrintString(DYNOS_TEXT_A, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 0);
}
} break;
}
}
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
if (aCurrentMenu == NULL) {
return;
}
// Colorful label
Label _Title;
if (aCurrentOption->mParent) {
_Title = get_title(aCurrentOption->mParent);
} else if (aCurrentMenu == aDynosMenu) {
_Title = DYNOS_TEXT_DYNOS_MENU;
} else if (aCurrentMenu == aOptionsMenu) {
_Title = DYNOS_TEXT_OPTIONS_MENU;
}
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
if (!_Title.second) _Title.second = DynOS_String_Convert(_Title.first.begin(), false);
print_hud_lut_string(HUD_LUT_GLOBAL, (SCREEN_WIDTH / 2 - DynOS_String_Length(_Title.second) * 6), 40, _Title.second);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
// Display options
DynosOption **_Options = GetCurrentOptions(aCurrentOption);
for (s32 i = 0; i != 7; ++i) {
DynOS_Opt_DrawOption(_Options[i], aCurrentOption, 156 - 20 * i);
}
// Scroll bar
s32 _OptCount = GetCurrentOptionCount(aCurrentOption);
s32 _OptIndex = GetCurrentOptionIndex(aCurrentOption);
if (_OptCount > 7) {
s32 _Height = (s32) (134.f * sqrtf(1.f / (_OptCount - 6)));
s32 _Y = 37 + (134 - _Height) * (1.f - MAX(0.f, MIN(1.f, (f32)(_OptIndex - 3) / (f32)(_OptCount - 6))));
PrintBox(OFFSET_FROM_RIGHT_EDGE - 16, 36, 8, 136, COLOR_DARK_GRAY, 0);
PrintBox(OFFSET_FROM_RIGHT_EDGE - 15, _Y, 6, _Height, COLOR_WHITE, 0);
}
}
#define PROMPT_OFFSET (56.25f * GFX_DIMENSIONS_ASPECT_RATIO)
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
if (aCurrentMenu == aOptionsMenu) {
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_CLOSE_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
} else if (aCurrentMenu == aDynosMenu) {
PrintString(DYNOS_TEXT_CLOSE_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
} else {
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
}
}

View File

@ -1,159 +0,0 @@
#include "dynos.cpp.h"
static DynosOption *sPrevOpt = NULL;
static DynosOption *sOptionsMenu = NULL;
//
// Vanilla actions
//
typedef void (*VanillaActionFunction)(struct Option *, s32);
typedef struct VanillaAction {
String mFuncName;
VanillaActionFunction mAction;
} VanillaAction;
STATIC_STORAGE(Array<VanillaAction *>, VanillaActions);
#define sVanillaActions __VanillaActions()
static VanillaActionFunction DynOS_Opt_GetVanillaAction(const String& aFuncName) {
for (auto &_DynosAction : sVanillaActions) {
if (_DynosAction->mFuncName == aFuncName) {
return _DynosAction->mAction;
}
}
return NULL;
}
static void DynOS_Opt_AddVanillaAction(const String& aFuncName, void (*aFuncPtr)(struct Option *, s32)) {
for (auto &_DynosAction : sVanillaActions) {
if (_DynosAction->mFuncName == aFuncName) {
return;
}
}
VanillaAction *_DynosAction = New<VanillaAction>();
_DynosAction->mFuncName = aFuncName;
_DynosAction->mAction = aFuncPtr;
sVanillaActions.Add(_DynosAction);
}
static bool DynOS_Opt_CallVanillaAction(const char *aOptName) {
VanillaActionFunction _Func = DynOS_Opt_GetVanillaAction(aOptName);
if (_Func) {
_Func(NULL, 0);
return true;
}
return false;
}
//
// Convert classic options menu into DynOS menu
//
static DynosOption *DynOS_Opt_ConvertOption(const u8 *aLabel, const u8 *aTitle) {
static u32 sOptIdx = 0;
DynosOption *_Opt = New<DynosOption>();
_Opt->mName = String("vanilla_opt_%08X", sOptIdx++);
_Opt->mConfigName = "";
_Opt->mLabel = { "", aLabel };
_Opt->mTitle = { "", aTitle };
_Opt->mDynos = false;
if (sPrevOpt == NULL) { // The very first option
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = NULL;
sOptionsMenu = _Opt;
} else {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
_Opt->mPrev = NULL;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt;
sPrevOpt->mSubMenu.mChild = _Opt;
sPrevOpt->mSubMenu.mEmpty = false;
} else {
_Opt->mPrev = sPrevOpt;
_Opt->mNext = NULL;
_Opt->mParent = sPrevOpt->mParent;
sPrevOpt->mNext = _Opt;
}
}
sPrevOpt = _Opt;
return _Opt;
}
static void DynOS_Opt_EndSubMenu() {
if (sPrevOpt) {
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
sPrevOpt->mSubMenu.mEmpty = false;
} else {
sPrevOpt = sPrevOpt->mParent;
}
}
}
static void DynOS_Opt_ConvertSubMenu(const u8 *aLabel, const u8 *aTitle) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aTitle);
_Opt->mType = DOPT_SUBMENU;
_Opt->mSubMenu.mChild = NULL;
_Opt->mSubMenu.mEmpty = true;
}
static void DynOS_Opt_ConvertToggle(const u8 *aLabel, bool *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_TOGGLE;
_Opt->mToggle.mTog = (bool *) pValue;
}
static void DynOS_Opt_ConvertScroll(const u8 *aLabel, s32 aMin, s32 aMax, s32 aStep, u32 *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_SCROLL;
_Opt->mScroll.mMin = aMin;
_Opt->mScroll.mMax = aMax;
_Opt->mScroll.mStep = aStep;
_Opt->mScroll.mValue = (s32 *) pValue;
}
static void DynOS_Opt_ConvertChoice(const u8 *aLabel, const u8 **aChoices, s32 aCount, u32 *pValue) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_CHOICE;
_Opt->mChoice.mIndex = (s32 *) pValue;
for (s32 i = 0; i != aCount; ++i) {
_Opt->mChoice.mChoices.Add({ "", aChoices[i] });
}
}
static void DynOS_Opt_ConvertButton(const u8 *aLabel, VanillaActionFunction aAction) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_BUTTON;
_Opt->mButton.mFuncName = "DynOS_Opt_CallVanillaAction";
DynOS_Opt_AddVanillaAction(_Opt->mName, aAction);
}
static void DynOS_Opt_ConvertBind(const u8 *aLabel, u32 *pBinds) {
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
_Opt->mType = DOPT_BIND;
_Opt->mBind.mMask = 0;
_Opt->mBind.mBinds = pBinds;
_Opt->mBind.mIndex = 0;
}
#ifndef COOP
extern "C" {
extern void dynos_opt_convert_vanilla_main_menu();
void dynos_opt_end_submenu() { return DynOS_Opt_EndSubMenu(); }
void dynos_opt_convert_submenu(const u8 *label, const u8 *title) { return DynOS_Opt_ConvertSubMenu(label, title); }
void dynos_opt_convert_toggle(const u8 *label, bool *bval) { return DynOS_Opt_ConvertToggle(label, bval); }
void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval) { return DynOS_Opt_ConvertScroll(label, min, max, step, uval); }
void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval) { return DynOS_Opt_ConvertChoice(label, choices, numChoices, uval); }
void dynos_opt_convert_button(const u8 *label, void *action) { return DynOS_Opt_ConvertButton(label, (VanillaActionFunction) action); }
void dynos_opt_convert_bind(const u8 *label, u32 *uval) { return DynOS_Opt_ConvertBind(label, uval); }
}
#endif
void DynOS_Opt_InitVanilla(DynosOption *&aOptionsMenu) {
sPrevOpt = NULL;
#ifndef COOP
dynos_opt_convert_vanilla_main_menu();
#endif
DynOS_Opt_AddAction("DynOS_Opt_CallVanillaAction", DynOS_Opt_CallVanillaAction, true);
aOptionsMenu = sOptionsMenu;
}

View File

@ -1,72 +0,0 @@
#ifndef COOP
// Not my problem
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsizeof-pointer-div"
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
#pragma GCC diagnostic ignored "-Wpointer-sign"
#pragma GCC diagnostic ignored "-Wsign-compare"
#define optmenu_toggle optmenu_toggle_unused
#define optmenu_draw optmenu_draw_unused
#define optmenu_draw_prompt optmenu_draw_prompt_unused
#define optmenu_check_buttons optmenu_check_buttons_unused
#define optmenu_open optmenu_open_unused
#define DYNOS_INL
#include "game/options_menu.c"
#undef DYNOS_INL
#undef optmenu_toggle
#undef optmenu_draw
#undef optmenu_draw_prompt
#undef optmenu_check_buttons
#undef optmenu_open
#pragma GCC diagnostic pop
// Now, that's my problem
extern void dynos_opt_end_submenu();
extern void dynos_opt_convert_submenu(const u8 *label, const u8 *title);
extern void dynos_opt_convert_toggle(const u8 *label, bool *bval);
extern void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval);
extern void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval);
extern void dynos_opt_convert_button(const u8 *label, void *action);
extern void dynos_opt_convert_bind(const u8 *label, u32 *uval);
static void dynos_opt_convert_menu(struct SubMenu *submenu) {
for (s32 i = 0; i != submenu->numOpts; ++i) {
struct Option *opt = &submenu->opts[i];
switch (opt->type) {
case OPT_TOGGLE:
dynos_opt_convert_toggle(opt->label, opt->bval);
break;
case OPT_CHOICE:
dynos_opt_convert_choice(opt->label, opt->choices, opt->numChoices, opt->uval);
break;
case OPT_SCROLL:
dynos_opt_convert_scroll(opt->label, opt->scrMin, opt->scrMax, opt->scrStep, opt->uval);
break;
case OPT_SUBMENU:
dynos_opt_convert_submenu(opt->label, opt->nextMenu->label);
dynos_opt_convert_menu(opt->nextMenu);
dynos_opt_end_submenu();
break;
case OPT_BIND:
dynos_opt_convert_bind(opt->label, opt->uval);
break;
case OPT_BUTTON:
dynos_opt_convert_button(opt->label, opt->actionFn);
break;
default:
break;
}
}
}
void dynos_opt_convert_vanilla_main_menu() {
dynos_opt_convert_menu(&menuMain);
}
#endif

View File

@ -10,7 +10,6 @@ extern "C" {
#include "game/level_update.h"
#include "game/sound_init.h"
#include "game/object_list_processor.h"
#include "game/options_menu.h"
#include "pc/network/packets/packet.h"
#include "pc/lua/smlua_hooks.h"
extern s8 gDialogBoxState;
@ -82,19 +81,18 @@ bool DynOS_Warp_RestartLevel() {
//
bool DynOS_Warp_ExitLevel(s32 aDelay) {
if (DynOS_Level_GetCourse(gCurrLevelNum) == COURSE_NONE) {
if (DynOS_Level_GetCourse(gCurrLevelNum) == COURSE_NONE || !DynOS_Level_GetWarpDeath(gCurrLevelNum, gCurrAreaIndex)) {
return false;
}
// Close the pause menu if it was open
optmenu_toggle();
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
// Cancel out every music/sound/sequence
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
stop_background_music(seqid);
stop_background_music(seqid);
}
play_shell_music();
stop_shell_music();
@ -106,7 +104,7 @@ bool DynOS_Warp_ExitLevel(s32 aDelay) {
// Play Mario head transition, and change play mode to avoid getting stuck on the pause menu
aDelay = MAX(1, aDelay);
gMarioState->invincTimer = -1;
play_transition(WARP_TRANSITION_FADE_INTO_MARIO, aDelay, 0x00, 0x00, 0x00);
play_transition(WARP_TRANSITION_FADE_INTO_COLOR, aDelay, 0x00, 0x00, 0x00);
set_play_mode(0);
sDynosExitLevelNum = gCurrLevelNum;
sDynosExitAreaNum = gCurrAreaIndex;
@ -114,19 +112,18 @@ bool DynOS_Warp_ExitLevel(s32 aDelay) {
}
bool DynOS_Warp_ToCastle(s32 aLevel) {
if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE) {
if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE || !DynOS_Level_GetWarpDeath(aLevel, 1)) {
return false;
}
// Close the pause menu if it was open
optmenu_toggle();
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
// Cancel out every music/sound/sequence
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
stop_background_music(seqid);
stop_background_music(seqid);
}
play_shell_music();
stop_shell_music();
@ -142,79 +139,6 @@ bool DynOS_Warp_ToCastle(s32 aLevel) {
return true;
}
//
// Params
//
const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex) {
static const char *sLevelParams[][5] = {
{ "", "", "", "", "" },
{ "None", "No Submarine, No Poles", "Submarine Only", "Poles Only", "Submarine And Poles" },
{ "None", "Water Level: Lowest", "Water Level: Low", "Water Level: High", "Water Level: Highest" },
{ "None", "Top Flooded", "Top Drained", "Top Flooded", "Top Drained" },
{ "None", "Clock Speed: Stopped", "Clock Speed: Slow", "Clock Speed: Fast", "Clock Speed: Random" },
};
switch (aLevel) {
case LEVEL_DDD: return sLevelParams[1][MIN(4, aIndex)];
case LEVEL_WDW: return sLevelParams[2][MIN(4, aIndex)];
case LEVEL_THI: return sLevelParams[3][MIN(4, aIndex)];
case LEVEL_TTC: return sLevelParams[4][MIN(4, aIndex)];
}
return sLevelParams[0][MIN(4, aIndex)];
}
// Called thrice
// Pass -1 to use the previous value (only once)
void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex) {
static s32 sDynosWarpPrevParamIndex = -1;
if (aIndex == -1) {
aIndex = sDynosWarpPrevParamIndex;
sDynosWarpPrevParamIndex = -1;
} else {
sDynosWarpPrevParamIndex = aIndex;
}
switch (aLevel) {
case LEVEL_DDD:
switch (aIndex) {
case 1: gDDDBowsersSub = 0; gDDDPoles = 0; break;
case 2: gDDDBowsersSub = 1; gDDDPoles = 0; break;
case 3: gDDDBowsersSub = 0; gDDDPoles = 1; break;
case 4: gDDDBowsersSub = 1; gDDDPoles = 1; break;
}
break;
case LEVEL_WDW:
if (gEnvironmentRegions && gEnvironmentRegionsLength > 6) {
switch (aIndex) {
case 1: gEnvironmentRegions[6] = *gEnvironmentLevels = 31; gWdwWaterLevelSet = 1; break;
case 2: gEnvironmentRegions[6] = *gEnvironmentLevels = 1024; gWdwWaterLevelSet = 1; break;
case 3: gEnvironmentRegions[6] = *gEnvironmentLevels = 1792; gWdwWaterLevelSet = 1; break;
case 4: gEnvironmentRegions[6] = *gEnvironmentLevels = 2816; gWdwWaterLevelSet = 1; break;
}
}
break;
case LEVEL_THI:
switch (aIndex) {
case 1: gTHIWaterDrained = 0; break;
case 2: gTHIWaterDrained = 1; break;
case 3: gTHIWaterDrained = 0; break;
case 4: gTHIWaterDrained = 1; break;
}
break;
case LEVEL_TTC:
switch (aIndex) {
case 1: gTTCSpeedSetting = TTC_SPEED_STOPPED; break;
case 2: gTTCSpeedSetting = TTC_SPEED_SLOW; break;
case 3: gTTCSpeedSetting = TTC_SPEED_FAST; break;
case 4: gTTCSpeedSetting = TTC_SPEED_RANDOM; break;
}
break;
}
}
//
// Update
//
@ -226,14 +150,13 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
if (sDynosWarpTargetArea == -1) {
// Close the pause menu if it was open
optmenu_toggle();
level_set_transition(0, NULL);
gDialogBoxState = 0;
gMenuMode = -1;
// Cancel out every music/sound/sequence
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
stop_background_music(seqid);
stop_background_music(seqid);
}
play_shell_music();
stop_shell_music();
@ -259,13 +182,10 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
gCurrLevelNum = sDynosWarpLevelNum;
gCurrCourseNum = DynOS_Level_GetCourse(gCurrLevelNum);
gSavedCourseNum = gCurrCourseNum;
gCurrActNum = MAX(1, sDynosWarpActNum * (gCurrCourseNum <= COURSE_STAGES_MAX));
gCurrActNum = MAX(0, sDynosWarpActNum * (gCurrCourseNum <= COURSE_STAGES_MAX));
gDialogCourseActNum = gCurrActNum;
gCurrAreaIndex = sDynosWarpAreaNum;
gCurrActStarNum = sDynosWarpActNum;
#ifndef COOP
DynOS_Warp_SetParam(gCurrLevelNum, DynOS_Opt_GetValue("dynos_warp_param"));
#endif
sDynosWarpTargetArea = gCurrAreaIndex;
// Set up new level script
@ -285,7 +205,7 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
}
// Phase 3 - End level initialization
if (aIsLevelInitDone) {
if (aIsLevelInitDone && gMarioObjects[0]) {
// Get Warp
s16 *_Warp;
@ -306,9 +226,6 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
gMarioSpawnInfo->areaIndex = gCurrAreaIndex;
init_mario();
set_mario_initial_action(gMarioState, sDynosWarpSpawnType, 0);
#ifndef COOP
DynOS_Warp_SetParam(gCurrLevelNum, DynOS_Opt_GetValue("dynos_warp_param"));
#endif
// Init transition
if (gCurrentArea != NULL) {
@ -447,7 +364,7 @@ static void *DynOS_Warp_UpdateExit(void *aCmd, bool aIsLevelInitDone) {
}
// Phase 3 - End level initialization
if (sDynosExitTargetWarp && aIsLevelInitDone) {
if (sDynosExitTargetWarp && aIsLevelInitDone && gMarioObjects[0]) {
// Find target position
// Because of course, every hack has its own warp distances and orientations...
@ -471,14 +388,18 @@ static void *DynOS_Warp_UpdateExit(void *aCmd, bool aIsLevelInitDone) {
set_mario_initial_action(gMarioState, MARIO_SPAWN_UNKNOWN_02, 0);
// Init transition
reset_camera(gCurrentArea->camera);
init_camera(gCurrentArea->camera);
if (gCurrentArea != NULL) {
reset_camera(gCurrentArea->camera);
init_camera(gCurrentArea->camera);
}
sDelayedWarpOp = WARP_OP_NONE;
play_transition(WARP_TRANSITION_FADE_FROM_STAR, 15, 0x00, 0x00, 0x00);
play_sound(SOUND_MENU_MARIO_CASTLE_WARP, gGlobalSoundSource);
// Set music
set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0);
if (gCurrentArea != NULL) {
set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0);
}
sDynosExitTargetWarp = NULL;
// lua hooks

View File

@ -7384,6 +7384,50 @@
<br />
## [collision_find_ceil](#collision_find_ceil)
### Lua Example
`local SurfaceValue = collision_find_ceil(x, y, z)`
### Parameters
| Field | Type |
| ----- | ---- |
| x | `number` |
| y | `number` |
| z | `number` |
### Returns
[Surface](structs.md#Surface)
### C Prototype
`struct Surface* collision_find_ceil(f32 x, f32 y, f32 z);`
[:arrow_up_small:](#)
<br />
## [collision_find_floor](#collision_find_floor)
### Lua Example
`local SurfaceValue = collision_find_floor(x, y, z)`
### Parameters
| Field | Type |
| ----- | ---- |
| x | `number` |
| y | `number` |
| z | `number` |
### Returns
[Surface](structs.md#Surface)
### C Prototype
`struct Surface* collision_find_floor(f32 x, f32 y, f32 z);`
[:arrow_up_small:](#)
<br />
## [collision_find_surface_on_ray](#collision_find_surface_on_ray)
### Lua Example
@ -7564,6 +7608,26 @@
<br />
## [smlua_level_util_get_info_from_course_num](#smlua_level_util_get_info_from_course_num)
### Lua Example
`local CustomLevelInfoValue = smlua_level_util_get_info_from_course_num(courseNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
### Returns
[CustomLevelInfo](structs.md#CustomLevelInfo)
### C Prototype
`struct CustomLevelInfo* smlua_level_util_get_info_from_course_num(u8 courseNum);`
[:arrow_up_small:](#)
<br />
## [smlua_level_util_get_info_from_short_name](#smlua_level_util_get_info_from_short_name)
### Lua Example

View File

@ -2384,6 +2384,91 @@
<br />
## [smlua_text_utils_act_name_get](#smlua_text_utils_act_name_get)
### Lua Example
`local stringValue = smlua_text_utils_act_name_get(courseNum, actNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| actNum | `integer` |
### Returns
- `string`
### C Prototype
`const char* smlua_text_utils_act_name_get(s16 courseNum, u8 actNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_act_name_is_modified](#smlua_text_utils_act_name_is_modified)
### Lua Example
`local booleanValue = smlua_text_utils_act_name_is_modified(courseNum, actNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| actNum | `integer` |
### Returns
- `boolean`
### C Prototype
`bool smlua_text_utils_act_name_is_modified(s16 courseNum, u8 actNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_act_name_replace](#smlua_text_utils_act_name_replace)
### Lua Example
`smlua_text_utils_act_name_replace(courseNum, actNum, name)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| actNum | `integer` |
| name | `string` |
### Returns
- None
### C Prototype
`void smlua_text_utils_act_name_replace(s16 courseNum, u8 actNum, const char* name);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_act_name_reset](#smlua_text_utils_act_name_reset)
### Lua Example
`smlua_text_utils_act_name_reset(courseNum, actNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| actNum | `integer` |
### Returns
- None
### C Prototype
`void smlua_text_utils_act_name_reset(s16 courseNum, u8 actNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_castle_secret_stars_replace](#smlua_text_utils_castle_secret_stars_replace)
### Lua Example
@ -2431,6 +2516,87 @@
<br />
## [smlua_text_utils_course_name_get](#smlua_text_utils_course_name_get)
### Lua Example
`local stringValue = smlua_text_utils_course_name_get(courseNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
### Returns
- `string`
### C Prototype
`const char* smlua_text_utils_course_name_get(s16 courseNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_course_name_mod_index](#smlua_text_utils_course_name_mod_index)
### Lua Example
`local integerValue = smlua_text_utils_course_name_mod_index(courseNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
### Returns
- `integer`
### C Prototype
`s32 smlua_text_utils_course_name_mod_index(s16 courseNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_course_name_replace](#smlua_text_utils_course_name_replace)
### Lua Example
`smlua_text_utils_course_name_replace(courseNum, name)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
| name | `string` |
### Returns
- None
### C Prototype
`void smlua_text_utils_course_name_replace(s16 courseNum, const char* name);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_course_name_reset](#smlua_text_utils_course_name_reset)
### Lua Example
`smlua_text_utils_course_name_reset(courseNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
### Returns
- None
### C Prototype
`void smlua_text_utils_course_name_reset(s16 courseNum);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_dialog_replace](#smlua_text_utils_dialog_replace)
### Lua Example
@ -2495,24 +2661,6 @@
<br />
## [smlua_text_utils_reset_all](#smlua_text_utils_reset_all)
### Lua Example
`smlua_text_utils_reset_all()`
### Parameters
- None
### Returns
- None
### C Prototype
`void smlua_text_utils_reset_all(void);`
[:arrow_up_small:](#)
<br />
## [smlua_text_utils_secret_star_replace](#smlua_text_utils_secret_star_replace)
### Lua Example

View File

@ -1521,6 +1521,8 @@
<br />
- smlua_collision_utils.h
- [collision_find_ceil](functions-4.md#collision_find_ceil)
- [collision_find_floor](functions-4.md#collision_find_floor)
- [collision_find_surface_on_ray](functions-4.md#collision_find_surface_on_ray)
- [collision_get_temp_wall_collision_data](functions-4.md#collision_get_temp_wall_collision_data)
- [get_water_surface_pseudo_floor](functions-4.md#get_water_surface_pseudo_floor)
@ -1537,6 +1539,7 @@
- [level_register](functions-4.md#level_register)
- [smlua_level_util_change_area](functions-4.md#smlua_level_util_change_area)
- [smlua_level_util_get_info](functions-4.md#smlua_level_util_get_info)
- [smlua_level_util_get_info_from_course_num](functions-4.md#smlua_level_util_get_info_from_course_num)
- [smlua_level_util_get_info_from_short_name](functions-4.md#smlua_level_util_get_info_from_short_name)
- [warp_exit_level](functions-4.md#warp_exit_level)
- [warp_restart_level](functions-4.md#warp_restart_level)
@ -1690,12 +1693,19 @@
<br />
- smlua_text_utils.h
- [smlua_text_utils_act_name_get](functions-5.md#smlua_text_utils_act_name_get)
- [smlua_text_utils_act_name_is_modified](functions-5.md#smlua_text_utils_act_name_is_modified)
- [smlua_text_utils_act_name_replace](functions-5.md#smlua_text_utils_act_name_replace)
- [smlua_text_utils_act_name_reset](functions-5.md#smlua_text_utils_act_name_reset)
- [smlua_text_utils_castle_secret_stars_replace](functions-5.md#smlua_text_utils_castle_secret_stars_replace)
- [smlua_text_utils_course_acts_replace](functions-5.md#smlua_text_utils_course_acts_replace)
- [smlua_text_utils_course_name_get](functions-5.md#smlua_text_utils_course_name_get)
- [smlua_text_utils_course_name_mod_index](functions-5.md#smlua_text_utils_course_name_mod_index)
- [smlua_text_utils_course_name_replace](functions-5.md#smlua_text_utils_course_name_replace)
- [smlua_text_utils_course_name_reset](functions-5.md#smlua_text_utils_course_name_reset)
- [smlua_text_utils_dialog_replace](functions-5.md#smlua_text_utils_dialog_replace)
- [smlua_text_utils_extra_text_replace](functions-5.md#smlua_text_utils_extra_text_replace)
- [smlua_text_utils_get_language](functions-5.md#smlua_text_utils_get_language)
- [smlua_text_utils_reset_all](functions-5.md#smlua_text_utils_reset_all)
- [smlua_text_utils_secret_star_replace](functions-5.md#smlua_text_utils_secret_star_replace)
<br />

View File

@ -154,32 +154,14 @@ static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surfac
/**
* Returns the lowest of three values.
*/
static s16 min_3(s16 a0, s16 a1, s16 a2) {
if (a1 < a0) {
a0 = a1;
}
if (a2 < a0) {
a0 = a2;
}
return a0;
}
#define min_3(a0, a1, a2) MIN(MIN(a0, a1), a2)
/**
* Returns the highest of three values.
*/
static s16 max_3(s16 a0, s16 a1, s16 a2) {
if (a1 > a0) {
a0 = a1;
}
if (a2 > a0) {
a0 = a2;
}
return a0;
}
#define max_3(a0, a1, a2) MAX(MAX(a0, a1), a2)
/**
* Every level is split into 16 * 16 cells of surfaces (to limit computing
@ -378,48 +360,25 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
* Returns whether a surface has exertion/moves Mario
* based on the surface type.
*/
static s32 surface_has_force(s16 surfaceType) {
s32 hasForce = FALSE;
switch (surfaceType) {
case SURFACE_0004: // Unused
case SURFACE_FLOWING_WATER:
case SURFACE_DEEP_MOVING_QUICKSAND:
case SURFACE_SHALLOW_MOVING_QUICKSAND:
case SURFACE_MOVING_QUICKSAND:
case SURFACE_HORIZONTAL_WIND:
case SURFACE_INSTANT_MOVING_QUICKSAND:
hasForce = TRUE;
break;
default:
break;
}
return hasForce;
static bool surface_has_force(s16 surfaceType) {
return surfaceType == SURFACE_0004 ||
surfaceType == SURFACE_FLOWING_WATER ||
surfaceType == SURFACE_HORIZONTAL_WIND ||
surfaceType == SURFACE_MOVING_QUICKSAND ||
surfaceType == SURFACE_DEEP_MOVING_QUICKSAND ||
surfaceType == SURFACE_SHALLOW_MOVING_QUICKSAND ||
surfaceType == SURFACE_INSTANT_MOVING_QUICKSAND;
}
/**
* Returns whether a surface should have the
* SURFACE_FLAG_NO_CAM_COLLISION flag.
*/
static s32 surf_has_no_cam_collision(s16 surfaceType) {
s32 flags = 0;
switch (surfaceType) {
case SURFACE_RAYCAST:
case SURFACE_NO_CAM_COLLISION:
case SURFACE_NO_CAM_COLLISION_77: // Unused
case SURFACE_NO_CAM_COL_VERY_SLIPPERY:
case SURFACE_VANISH_CAP_WALLS:
case SURFACE_SWITCH:
flags = SURFACE_FLAG_NO_CAM_COLLISION;
break;
default:
break;
}
return flags;
static bool surf_has_no_cam_collision(s16 surfaceType) {
return surfaceType == SURFACE_SWITCH ||
surfaceType == SURFACE_NO_CAM_COLLISION ||
surfaceType == SURFACE_NO_CAM_COLLISION_77 ||
surfaceType == SURFACE_NO_CAM_COL_VERY_SLIPPERY;
}
/**
@ -427,17 +386,16 @@ static s32 surf_has_no_cam_collision(s16 surfaceType) {
* exertion, and room.
*/
static void load_static_surfaces(s16 **data, s16 *vertexData, s16 surfaceType, s8 **surfaceRooms) {
s32 i;
s32 numSurfaces;
struct Surface *surface;
s8 room = 0;
s16 hasForce = surface_has_force(surfaceType);
s16 flags = surf_has_no_cam_collision(surfaceType);
bool hasForce = surface_has_force(surfaceType);
bool flags = surf_has_no_cam_collision(surfaceType);
numSurfaces = *(*data);
*data += 1;
for (i = 0; i < numSurfaces; i++) {
for (s32 i = 0; i < numSurfaces; i++) {
if (*surfaceRooms != NULL) {
room = *(*surfaceRooms);
*surfaceRooms += 1;
@ -486,7 +444,6 @@ static s16 *read_vertex_data(s16 **data) {
*/
static void load_environmental_regions(s16 **data) {
s32 numRegions;
s32 i;
gEnvironmentRegionsLength = 0;
gEnvironmentRegions = *data;
@ -497,7 +454,7 @@ static void load_environmental_regions(s16 **data) {
numRegions = 20;
}
for (i = 0; i < numRegions; i++) {
for (s32 i = 0; i < numRegions; i++) {
UNUSED s16 val, loX, loZ, hiX, hiZ;
s16 height;

View File

@ -30,7 +30,7 @@ static void bhv_camera_lakitu_on_received_post(u8 localIndex) {
void bhv_camera_lakitu_init(void) {
if (o->oBehParams2ndByte != CAMERA_LAKITU_BP_FOLLOW_CAMERA) {
// Despawn unless this is the very beginning of the game
if (gNeverEnteredCastle != TRUE) {
if (!gNeverEnteredCastle) {
obj_mark_for_deletion(o);
return;
}
@ -38,7 +38,7 @@ void bhv_camera_lakitu_init(void) {
spawn_object_relative_with_scale(CLOUD_BP_LAKITU_CLOUD, 0, 0, 0, 2.0f, o, MODEL_MIST, bhvCloud);
}
lakituTargetLocalIndex = UNKNOWN_LOCAL_INDEX;
if (!sync_object_is_initialized(o->oSyncID)) {
struct SyncObject *so = sync_object_init(o, 4000.0f);
if (so) {

View File

@ -131,23 +131,20 @@ static u8 bhv_snowmans_bottom_loop_continue_dialog(void) {
}
void bhv_snowmans_bottom_loop(void) {
s16 sp1E;
struct MarioState* marioState = nearest_mario_state_to_object(o);
switch (o->oAction) {
case 0:
if (marioState
&& marioState->playerIndex == 0
&& should_start_or_continue_dialog(marioState, o)
&& (is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 400) == 1)
&& set_mario_npc_dialog(&gMarioStates[0], 1, bhv_snowmans_bottom_loop_continue_dialog) == 2) {
sp1E = cutscene_object_with_dialog(CUTSCENE_DIALOG, o, gBehaviorValues.dialogs.SnowmanHeadBodyDialog);
if (sp1E) {
o->oForwardVel = 10.0f;
o->oAction = 1;
set_mario_npc_dialog(&gMarioStates[0], 0, NULL);
network_send_object(o);
}
&& set_mario_npc_dialog(&gMarioStates[0], 1, bhv_snowmans_bottom_loop_continue_dialog)
&& cutscene_object_with_dialog(CUTSCENE_DIALOG, o, gBehaviorValues.dialogs.SnowmanHeadBodyDialog)) {
o->oForwardVel = 10.0f;
o->oAction = 1;
set_mario_npc_dialog(&gMarioStates[0], 0, NULL);
network_send_object(o);
}
break;

View File

@ -59,10 +59,10 @@ static struct ObjectHitbox sCollectStarHitbox = {
};
void bhv_collect_star_init(void) {
s8 starId;
s16 starId;
u8 currentLevelStarFlags;
starId = (o->oBehParams >> 24) & 0xFF;
starId = o->oBehParams >> 24;
currentLevelStarFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1);
if (currentLevelStarFlags & (1 << starId)) {
cur_obj_set_model(MODEL_TRANSPARENT_STAR);
@ -256,7 +256,7 @@ struct Object *spawn_no_exit_star(f32 x, f32 y, f32 z) {
/**
* A special star spawning routine just for a networked stars.
* These stars require the global index for a network player for proper
* cutscene functionality.
* cutscene functionality.
*/
struct Object *spawn_networked_default_star(f32 x, f32 y, f32 z, u8 networkPlayerIndex) {
if (sCurrPlayMode != PLAY_MODE_NORMAL && sCurrPlayMode != PLAY_MODE_PAUSED) { return NULL; }
@ -298,7 +298,7 @@ void bhv_hidden_red_coin_star_init(void) {
if (gCurrentArea) {
o->oHiddenStarTriggerCounter = gCurrentArea->numRedCoins - redCoins;
}
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
// but it also is only set for an interaction.
@ -306,7 +306,7 @@ void bhv_hidden_red_coin_star_init(void) {
// and if it wasn't. You couldn't of possibly been the one
// who last interacted to begin with.
o->oHiddenStarLastInteractedObject = NULL;
if (!sync_object_is_initialized(o->oSyncID)) {
struct SyncObject *so = sync_object_init(o, SYNC_DISTANCE_ONLY_EVENTS);
if (so) {

View File

@ -3112,10 +3112,12 @@ void update_lakitu(struct Camera *c) {
gLakituState.defMode = c->defMode;
}
extern bool gIsDemoActive;
static void update_romhack_camera_override(struct Camera *c) {
if (gOverrideRomhackCamera == RCO_NONE) { return; }
if (c->mode == CAMERA_MODE_ROM_HACK) { return; }
if (dynos_level_is_vanilla_level(gCurrLevelNum)) { return; }
if (gIsDemoActive) { return; }
if (gOverrideRomhackCamera == RCO_ALL_EXCEPT_BOWSER) {
if (gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2 || gCurrLevelNum == LEVEL_BOWSER_3) {
@ -3516,7 +3518,7 @@ void init_camera(struct Camera *c) {
// Make sure Bowser is in a state that we'd start speaking to him in.
obj = find_object_with_behavior(bhvBowser);
if (obj != NULL && obj->oAction != 5) { break; }
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
} else if (gSecondCameraFocus != NULL) {
gSecondCameraFocus->oBowserUnk88 = 2;
@ -3525,7 +3527,7 @@ void init_camera(struct Camera *c) {
// Make sure Bowser is in a state that we'd start speaking to him in.
obj = find_object_with_behavior(bhvBowser);
if (obj != NULL && obj->oAction != 5) { break; }
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
#endif
break;
@ -3533,14 +3535,14 @@ void init_camera(struct Camera *c) {
// Make sure Bowser is in a state that we'd start speaking to him in.
obj = find_object_with_behavior(bhvBowser);
if (obj != NULL && obj->oAction != 5) { break; }
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
break;
case LEVEL_BOWSER_3:
// Make sure Bowser is in a state that we'd start speaking to him in.
obj = find_object_with_behavior(bhvBowser);
if (obj != NULL && obj->oAction != 5) { break; }
start_cutscene(c, CUTSCENE_ENTER_BOWSER_ARENA);
break;
@ -9605,7 +9607,7 @@ BAD_RETURN(s32) cutscene_non_painting_set_cam_pos(struct Camera *c) {
BAD_RETURN(s32) cutscene_non_painting_set_cam_focus(struct Camera *c) {
if (!c) { return; }
offset_rotated(c->focus, sCutsceneVars[7].point, sCutsceneVars[6].point, sCutsceneVars[7].angle);
if (dynos_level_is_vanilla_level(gCurrLevelNum) && ((gPrevLevel == LEVEL_COTMC) || (gPrevLevel == LEVEL_HMC) || (gPrevLevel == LEVEL_RR) || (gPrevLevel == LEVEL_WMOTR))) {
c->focus[0] = c->pos[0] + (sMarioCamState->pos[0] - c->pos[0]) * 0.7f;
c->focus[1] = c->pos[1] + (sMarioCamState->pos[1] - c->pos[1]) * 0.4f;

View File

@ -468,7 +468,6 @@ void read_controller_inputs(void) {
if (gControllerBits) {
osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK);
osContGetReadData(gInteractableOverridePad ? &gInteractablePad : &gControllerPads[0]);
dynos_update_opt((void *) &gControllerPads[0]);
}
run_demo_inputs();

View File

@ -34,6 +34,8 @@
#include "levels/wf/header.h"
#include "levels/wmotr/header.h"
#include "src/pc/pc_main.h"
extern Trajectory sThiHugeMetalBallTraj[];
extern Trajectory sThiTinyMetalBallTraj[];
@ -308,8 +310,7 @@ struct PaintingValues gPaintingValues = { 0 };
// functions //
///////////////
__attribute__((constructor))
void hardcoded_reset_default_values(void) {
AT_STARTUP void hardcoded_reset_default_values(void) {
gLevelValues = gDefaultLevelValues;
gBehaviorValues = gDefaultBehaviorValues;

View File

@ -39,6 +39,7 @@
#ifdef BETTERCAMERA
#include "bettercamera.h"
#endif
#include "level_info.h"
u16 gDialogColorFadeTimer;
s8 gLastDialogLineNum;
@ -2515,38 +2516,13 @@ void render_pause_my_score_coins(void) {
u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR };
u8 strCourseNum[4];
void **courseNameTbl;
u8 *courseName;
void **actNameTbl;
u8 *actName = NULL;
u8 courseIndex;
u8 courseIndex = gCurrCourseNum - 1;
u8 *courseName = (u8*) get_level_name_sm64(gCurrCourseNum, gCurrLevelNum, gCurrAreaIndex, 1);
u8 *actName = (u8*) get_star_name_sm64(gCurrCourseNum, gDialogCourseActNum, 1);
u8 starFlags;
#ifndef VERSION_EU
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
actNameTbl = segmented_to_virtual(seg2_act_name_table);
#endif
courseIndex = gCurrCourseNum - 1;
starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1);
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#endif
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
@ -2564,8 +2540,6 @@ void render_pause_my_score_coins(void) {
print_generic_string(MYSCORE_X, 121, textMyScore);
}
courseName = segmented_to_virtual(courseNameTbl[courseIndex]);
if (courseIndex < COURSE_STAGES_COUNT) {
#ifdef VERSION_EU
print_generic_string(48, 157, gTextCourseArr[gInGameLanguage]);
@ -2579,10 +2553,6 @@ void render_pause_my_score_coins(void) {
print_generic_string(CRS_NUM_X1, 157, strCourseNum);
#endif
if (gDialogCourseActNum >= 1 && gDialogCourseActNum <= 6) {
actName = segmented_to_virtual(actNameTbl[(gCurrCourseNum - 1) * 6 + gDialogCourseActNum - 1]);
}
if (starFlags & (1 << (gDialogCourseActNum - 1))) {
print_generic_string(TXT_STAR_X, 140, textStar);
} else {
@ -2838,11 +2808,7 @@ void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum)
}
void render_pause_castle_main_strings(s16 x, s16 y) {
#ifdef VERSION_EU
void **courseNameTbl;
#else
void **courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
void **courseNameTbl = get_course_name_table();
#ifdef VERSION_EU
u8 textCoin[] = { TEXT_COIN };
@ -2856,20 +2822,6 @@ void render_pause_castle_main_strings(s16 x, s16 y) {
u8 strVal[8];
s16 starNum = gDialogLineNum;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#endif
handle_menu_scrolling(MENU_SCROLL_VERTICAL, &gDialogLineNum, -1, COURSE_STAGES_COUNT + 1);
if (gDialogLineNum == COURSE_STAGES_COUNT + 1) {
@ -2936,7 +2888,7 @@ void render_pause_castle_main_strings(s16 x, s16 y) {
static u32 pause_castle_get_stars(s32 index) {
// Main courses (0-14), Secret courses (15-24)
if (index >= 0 && index < INDEX_CASTLE_STARS) {
if (COURSE_IS_VALID_COURSE(index)) {
return save_file_get_star_flags(gCurrSaveFileNum - 1, index);
}
@ -3061,24 +3013,8 @@ void render_pause_castle_main_strings_extended(s16 x, s16 y) {
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#else
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
void **courseNameTbl = get_course_name_table();
// Main courses (0-14)
if (gDialogLineNum < COURSE_STAGES_COUNT) {
@ -3098,7 +3034,7 @@ void render_pause_castle_main_strings_extended(s16 x, s16 y) {
render_pause_castle_course_name(courseName + 3, 160, y + 30);
render_pause_castle_course_stars_extended(x + 20, y);
}
// Castle stars (25)
else if (gDialogLineNum == INDEX_CASTLE_STARS) {
const u8 *courseName = courseNameTbl[COURSE_MAX];
@ -3150,7 +3086,7 @@ s16 render_pause_courses_and_castle(void) {
play_sound(SOUND_MENU_PAUSE_HIGHPRIO, gGlobalSoundSource);
#endif
if (gCurrCourseNum >= COURSE_MIN && gCurrCourseNum <= COURSE_MAX) {
if (COURSE_IS_VALID_COURSE(gCurrCourseNum)) {
change_dialog_camera_angle();
gDialogBoxState = DIALOG_STATE_VERTICAL;
} else {
@ -3227,14 +3163,9 @@ s16 render_pause_courses_and_castle(void) {
}
if (gDjuiPanelPauseCreated) { shade_screen(); }
if (gPlayer1Controller->buttonPressed & R_TRIG)
if (gPlayer1Controller->buttonPressed & R_TRIG) {
djui_panel_pause_create(NULL);
#ifndef COOP
// call into DynOS's menu system
optmenu_draw();
optmenu_draw_prompt();
#endif
}
return 0;
}
@ -3384,33 +3315,12 @@ void render_course_complete_lvl_info_and_hud_str(void) {
u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE };
#endif
void **actNameTbl;
void **courseNameTbl;
void **actNameTbl = get_act_name_table();
void **courseNameTbl = get_course_name_table();
u8 *name;
u8 strCourseNum[4];
#ifdef VERSION_EU
s16 centerX;
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#else
actNameTbl = segmented_to_virtual(seg2_act_name_table);
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
if (gLastCompletedCourseNum <= COURSE_STAGES_MAX) {
print_hud_course_complete_coins(118, 103);
play_star_fanfare_and_flash_hud(1, 1 << (gLastCompletedStarNum - 1));
@ -3435,7 +3345,7 @@ void render_course_complete_lvl_info_and_hud_str(void) {
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha);
#ifdef VERSION_EU
centerX = get_str_x_pos_from_center(153, name, 12.0f);
s16 centerX = get_str_x_pos_from_center(153, name, 12.0f);
#endif
print_generic_string(TXT_NAME_X1, 130, name);
#ifndef VERSION_EU

View File

@ -923,12 +923,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O
u8 stayInLevelCommon = !(gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2 || gCurrLevelNum == LEVEL_BOWSER_3);
if (stayInLevelCommon && gServerSettings.stayInLevelAfterStar) { noExit = TRUE; }
if (o->behavior == bhvBowserKey) {
gLastCollectedStarOrKey = 1;
} else {
gLastCollectedStarOrKey = 0;
}
gLastCollectedStarOrKey = o->behavior == bhvBowserKey;
if (m->health >= 0x100) {
@ -981,7 +976,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O
m->interactObj = o;
m->usedObj = o;
starIndex = (o->oBehParams >> 24) & 0x1F;
starIndex = o->oBehParams >> 24;
if (m == &gMarioStates[0]) {
// sync the star collection

View File

@ -9,6 +9,7 @@
#include "save_file.h"
#include "types.h"
#include "pc/lua/utils/smlua_level_utils.h"
#include "pc/lua/utils/smlua_text_utils.h"
#ifdef VERSION_EU
extern s32 gInGameLanguage;
@ -39,7 +40,7 @@ static const struct { const char *str; u8 c; } sSm64CharMap[] = {
{ "p", 0x33 }, { "q", 0x34 }, { "r", 0x35 }, { "s", 0x36 }, { "t", 0x37 },
{ "u", 0x38 }, { "v", 0x39 }, { "w", 0x3A }, { "x", 0x3B }, { "y", 0x3C },
{ "z", 0x3D },
// Punctuation
{ "...", 0xE6 }, // ellipsis
{ ")(", 0xE2 }, // close-open parentheses
@ -57,7 +58,7 @@ static const struct { const char *str; u8 c; } sSm64CharMap[] = {
{ "%", 0xF3 }, // percent
{ "?", 0xF4 }, // question mark
{ "~", 0xF7 }, // tilde
// Symbols
{ "[A]", 0x54 }, // bold A
{ "[B]", 0x55 }, // bold B
@ -107,7 +108,7 @@ static void convert_string_ascii_to_sm64(u8 *str64, const char *strAscii) {
*str64 = 0xFF;
}
static void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64) {
void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64) {
for (; *str64 != 0xFF; str64++) {
strAscii = sm64_to_ascii_char(strAscii, str64);
}
@ -158,12 +159,40 @@ static void decapitalize_string_sm64(u8 *str64) {
}
}
void *get_course_name_table() {
void **courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: courseNameTbl = segmented_to_virtual(course_name_table_eu_en); break;
case LANGUAGE_FRENCH: courseNameTbl = segmented_to_virtual(course_name_table_eu_fr); break;
case LANGUAGE_GERMAN: courseNameTbl = segmented_to_virtual(course_name_table_eu_de); break;
}
#endif
return courseNameTbl;
}
void *get_act_name_table() {
void **actNameTbl = segmented_to_virtual(seg2_act_name_table);
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: actNameTbl = segmented_to_virtual(act_name_table_eu_en); break;
case LANGUAGE_FRENCH: actNameTbl = segmented_to_virtual(act_name_table_eu_fr); break;
case LANGUAGE_GERMAN: actNameTbl = segmented_to_virtual(act_name_table_eu_de); break;
}
#endif
return actNameTbl;
}
extern struct CourseName *gReplacedActNameTable[];
const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase) {
static char output[256];
// Valid course: BOB to RR, Bowser stages and Secret courses
// There is no course name for Cake Ending, make it defaults to "Peach's Castle"
// Custom course
bool hasCustomName = false;
if (levelNum >= CUSTOM_LEVEL_NUM_START) {
struct CustomLevelInfo* info = smlua_level_util_get_info(levelNum);
@ -173,41 +202,39 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
}
}
if (!hasCustomName && courseNum >= COURSE_MIN && courseNum < COURSE_MAX) {
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: courseNameTbl = segmented_to_virtual(course_name_table_eu_en); break;
case LANGUAGE_FRENCH: courseNameTbl = segmented_to_virtual(course_name_table_eu_fr); break;
case LANGUAGE_GERMAN: courseNameTbl = segmented_to_virtual(course_name_table_eu_de); break;
}
#else
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
const u8 *courseName = segmented_to_virtual(courseNameTbl[courseNum - COURSE_BOB]);
convert_string_sm64_to_ascii(output, courseName + 3);
if (gReplacedActNameTable[courseNum]->modIndex != -1) {
snprintf(output, 256, "%s", gReplacedActNameTable[courseNum]->name);
}
// Castle level
else if (!hasCustomName && courseNum == COURSE_NONE) {
switch (levelNum) {
case LEVEL_CASTLE: {
switch (areaIndex) {
case 1: snprintf(output, 256, "Castle Main Floor"); break;
case 2: snprintf(output, 256, "Castle Upper Floor"); break;
case 3: snprintf(output, 256, "Castle Basement"); break;
default: snprintf(output, 256, "Castle Purgatory"); break;
}
} break;
case LEVEL_CASTLE_GROUNDS: snprintf(output, 256, "Castle Grounds"); break;
case LEVEL_CASTLE_COURTYARD: snprintf(output, 256, "Castle Courtyard"); break;
default: snprintf(output, 256, "Peach's Castle");
}
}
// Default
else if (!hasCustomName) {
snprintf(output, 256, "Peach's Castle");
if (COURSE_IS_VALID_COURSE(courseNum)) {
void **courseNameTbl = get_course_name_table();
const u8 *courseName = segmented_to_virtual(courseNameTbl[courseNum - COURSE_BOB]);
convert_string_sm64_to_ascii(output, courseName + 3);
charCase = MIN(charCase, 0); // Don't need to capitalize vanilla course names
}
// Castle level
else if (courseNum == COURSE_NONE) {
switch (levelNum) {
case LEVEL_CASTLE: {
switch (areaIndex) {
case 1: snprintf(output, 256, "Castle Main Floor"); break;
case 2: snprintf(output, 256, "Castle Upper Floor"); break;
case 3: snprintf(output, 256, "Castle Basement"); break;
default: snprintf(output, 256, "Castle Purgatory"); break;
}
} break;
case LEVEL_CASTLE_GROUNDS: snprintf(output, 256, "Castle Grounds"); break;
case LEVEL_CASTLE_COURTYARD: snprintf(output, 256, "Castle Courtyard"); break;
default: snprintf(output, 256, "Peach's Castle");
}
}
// Default
else {
snprintf(output, 256, "Peach's Castle");
}
}
// Capitalize or decapitalize text
@ -221,7 +248,8 @@ const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16
const u8 *get_level_name_sm64(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase) {
static u8 output[256];
const char *levelName = get_level_name_ascii(courseNum, levelNum, areaIndex, charCase);
char levelName[256];
snprintf(levelName, 256, " %d %s", courseNum, (char*) get_level_name_ascii(courseNum, levelNum, areaIndex, charCase));
convert_string_ascii_to_sm64(output, levelName);
return output;
}
@ -233,28 +261,24 @@ const char *get_level_name(s16 courseNum, s16 levelNum, s16 areaIndex) {
const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase) {
static char output[256];
if (gReplacedActNameTable[courseNum]->actName && gReplacedActNameTable[courseNum]->actName[starNum - 1].isModified) {
snprintf(output, 256, "%s", gReplacedActNameTable[courseNum]->actName[starNum - 1].name);
}
// Main courses: BOB to RR
if (COURSE_IS_MAIN_COURSE(courseNum)) {
else if (COURSE_IS_MAIN_COURSE(courseNum)) {
if (starNum >= 1 && starNum <= 6) {
void **actNameTable = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH: actNameTable = segmented_to_virtual(act_name_table_eu_en); break;
case LANGUAGE_FRENCH: actNameTable = segmented_to_virtual(act_name_table_eu_fr); break;
case LANGUAGE_GERMAN: actNameTable = segmented_to_virtual(act_name_table_eu_de); break;
}
#else
actNameTable = segmented_to_virtual(seg2_act_name_table);
#endif
void **actNameTable = get_act_name_table();
const u8 *starName = segmented_to_virtual(actNameTable[(courseNum - COURSE_BOB) * 6 + (starNum - 1)]);
convert_string_sm64_to_ascii(output, starName);
charCase = MIN(charCase, 0); // Don't need to capitalize vanilla act names
} else if (starNum == 7) {
snprintf(output, 256, "%d Coins Star", (s32) gLevelValues.coinsRequiredForCoinStar);
snprintf(output, 256, "%d Coins Star", gLevelValues.coinsRequiredForCoinStar);
} else {
snprintf(output, 256, "A Secret Star!");
}
}
// Castle stars: Toads' and Mips'
else if (courseNum == COURSE_NONE) {
switch (starNum) {
@ -271,7 +295,7 @@ const char *get_star_name_ascii(s16 courseNum, s16 starNum, s16 charCase) {
else if (courseNum <= COURSE_MAX) {
snprintf(output, 256, "Star %d", starNum);
}
// Default
else {
snprintf(output, 256, "A Secret Star!");

View File

@ -3,6 +3,8 @@
#include <PR/ultratypes.h>
void *get_course_name_table();
void *get_act_name_table();
const char *get_level_name_ascii(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);
const u8 *get_level_name_sm64(s16 courseNum, s16 levelNum, s16 areaIndex, s16 charCase);
const char *get_level_name(s16 courseNum, s16 levelNum, s16 areaIndex);

View File

@ -69,7 +69,7 @@ s16 gChangeLevelTransition = -1;
s16 gChangeActNum = -1;
static bool sFirstCastleGroundsMenu = true;
static bool sIsDemoActive = false;
bool gIsDemoActive = false;
bool gInPlayerMenu = false;
static u16 gDemoCountdown = 0;
static int sDemoNumber = -1;
@ -201,7 +201,7 @@ s32 sDelayedWarpArg;
s16 unusedEULevelUpdateBss1;
#endif
s8 sTimerRunning;
s8 gNeverEnteredCastle;
bool gNeverEnteredCastle;
struct MarioState *gMarioState = &gMarioStates[0];
u8 unused1[4] = { 0 };
@ -1158,10 +1158,10 @@ bool find_demo_number(void) {
}
static void start_demo(void) {
if (sIsDemoActive) {
sIsDemoActive = false;
if (gIsDemoActive) {
gIsDemoActive = false;
} else {
sIsDemoActive = true;
gIsDemoActive = true;
if (find_demo_number()) {
gChangeLevel = gCurrLevelNum;
@ -1173,14 +1173,14 @@ static void start_demo(void) {
load_patchable_table(&gDemo, sDemoNumber);
gCurrDemoInput = ((struct DemoInput *) gDemo.targetAnim);
} else {
sIsDemoActive = false;
gIsDemoActive = false;
}
}
}
void stop_demo(UNUSED struct DjuiBase* caller) {
if (sIsDemoActive) {
sIsDemoActive = false;
if (gIsDemoActive) {
gIsDemoActive = false;
gCurrDemoInput = NULL;
gChangeLevel = gCurrLevelNum;
gDemoCountdown = 0;
@ -1197,22 +1197,26 @@ s32 play_mode_normal(void) {
if (gCurrDemoInput != NULL) {
print_intro_text();
if (gPlayer1Controller->buttonPressed & END_DEMO) {
level_trigger_warp(gMarioState,
gCurrLevelNum == LEVEL_PSS ? WARP_OP_DEMO_END : WARP_OP_DEMO_NEXT);
} else if (!gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE
&& (gPlayer1Controller->buttonPressed & START_BUTTON)) {
level_trigger_warp(gMarioState, gCurrLevelNum == LEVEL_PSS ? WARP_OP_DEMO_END : WARP_OP_DEMO_NEXT);
} else if (!gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE && (gPlayer1Controller->buttonPressed & START_BUTTON)) {
gPressedStart = 1;
level_trigger_warp(gMarioState, WARP_OP_DEMO_NEXT);
}
}
} else {
if (gDjuiInMainMenu && gCurrDemoInput == NULL && configMenuDemos && !gInPlayerMenu) {
if ((++gDemoCountdown) == PRESS_START_DEMO_TIMER && (find_demo_number() && (sDemoNumber <= 6 && sDemoNumber > -1))) {
start_demo();
}
if (gDjuiInMainMenu &&
gCurrDemoInput == NULL &&
configMenuDemos &&
!gInPlayerMenu &&
(++gDemoCountdown) == PRESS_START_DEMO_TIMER &&
(find_demo_number() && (sDemoNumber <= 6 && sDemoNumber > -1)) &&
gNetworkType == NT_NONE) {
start_demo();
}
if (((gCurrDemoInput != NULL) && (gPlayer1Controller->buttonPressed & END_DEMO || !sIsDemoActive || !gDjuiInMainMenu || gNetworkType != NT_NONE || gInPlayerMenu)) || (gCurrDemoInput == NULL && sIsDemoActive)) {
if (((gCurrDemoInput != NULL) &&
(gPlayer1Controller->buttonPressed & END_DEMO || !gIsDemoActive || !gDjuiInMainMenu || gNetworkType != NT_NONE || gInPlayerMenu)) ||
(gCurrDemoInput == NULL && gIsDemoActive)) {
gPlayer1Controller->buttonPressed &= ~END_DEMO;
stop_demo(NULL);
}
@ -1442,7 +1446,7 @@ void update_menu_level(void) {
// warp to level, this feels buggy
if (gCurrLevelNum != curLevel) {
if (sIsDemoActive) {
if (gIsDemoActive) {
stop_demo(NULL);
}
@ -1450,7 +1454,7 @@ void update_menu_level(void) {
gChangeActNum = 6;
gDemoCountdown = 0;
}
if (sIsDemoActive) {
if (gIsDemoActive) {
return;
}
@ -1462,7 +1466,7 @@ void update_menu_level(void) {
// set sFirstCastleGroundsMenu to false to prevent wall hugging bug
if (curLevel != LEVEL_CASTLE_GROUNDS) {
sFirstCastleGroundsMenu = false;
sFirstCastleGroundsMenu = false;
}
struct Object *o;
@ -1837,7 +1841,7 @@ s32 lvl_set_current_level(UNUSED s16 arg0, s32 levelNum) {
sWarpCheckpointActive = FALSE;
gCurrLevelNum = levelNum;
gCurrCourseNum = get_level_course_num(levelNum - 1);
gCurrCourseNum = get_level_course_num(levelNum);
bool foundHook = false;
bool hookUseActSelect = false;

View File

@ -124,7 +124,7 @@ struct HudDisplay {
};
extern struct HudDisplay gHudDisplay;
extern s8 gNeverEnteredCastle;
extern bool gNeverEnteredCastle;
extern u32 gControlTimerStartNat;
extern u32 gControlTimerStopNat;

View File

@ -1577,6 +1577,7 @@ copyPlayerGoto:;
if (m == m2) { continue; }
find_floor(m2->pos[0], m2->pos[1], m2->pos[2], &floor2);
if (floor2 == NULL) { continue; }
LOG_INFO("OOB! teleporting to player with local index %d", i);
vec3f_copy(m->pos, m2->pos);
copiedPlayer = TRUE;
goto copyPlayerGoto;

View File

@ -349,6 +349,7 @@ void cutscene_put_cap_on(struct MarioState *m) {
m->flags &= ~MARIO_CAP_IN_HAND;
m->flags |= MARIO_CAP_ON_HEAD;
play_sound(SOUND_ACTION_UNKNOWN43E, m->marioObj->header.gfx.cameraToObject);
m->cap = 0;
}
/**
@ -524,10 +525,10 @@ s32 act_disappeared(struct MarioState *m) {
s32 act_reading_automatic_dialog(struct MarioState *m) {
if (m == NULL) { return TRUE; }
// Increment our action state to continue our 'cutscene'.
m->actionState++;
if (m->actionState == 2) {
enable_time_stop_if_alone();
}
@ -556,7 +557,7 @@ s32 act_reading_automatic_dialog(struct MarioState *m) {
} else if (m->actionState == 25) { // finished action
disable_time_stop();
if (gNeverEnteredCastle) {
gNeverEnteredCastle = FALSE;
gNeverEnteredCastle = false;
play_cutscene_music(SEQUENCE_ARGS(0, SEQ_LEVEL_INSIDE_CASTLE));
}
if (m->prevAction == ACT_STAR_DANCE_WATER) {
@ -567,7 +568,7 @@ s32 act_reading_automatic_dialog(struct MarioState *m) {
}
}
}
// apply head turn
vec3s_set(m->marioBodyState->headAngle, m->actionTimer, 0, 0);
return FALSE;
@ -575,9 +576,9 @@ s32 act_reading_automatic_dialog(struct MarioState *m) {
s32 act_reading_sign(struct MarioState *m) {
if (m == NULL) { return TRUE; }
struct Object *marioObj = m->marioObj;
// If anybody but us is reading a sign,
// Don't handle their action state.
if (m->playerIndex != 0) {
@ -628,11 +629,11 @@ s32 act_reading_sign(struct MarioState *m) {
s32 act_debug_free_move(struct MarioState *m) {
if (m == NULL) { return TRUE; }
u32 action = ACT_IDLE;
#ifndef DEVELOPMENT
if (gNetworkType == NT_SERVER && gServerSettings.enableCheats == 0 && m->action == ACT_DEBUG_FREE_MOVE) {
if (gServerSettings.enableCheats == 0) {
if (m->pos[1] <= m->waterLevel - 100) {
action = ACT_WATER_IDLE;
} else {
@ -690,7 +691,7 @@ s32 act_debug_free_move(struct MarioState *m) {
void general_star_dance_handler(struct MarioState *m, s32 isInWater) {
if (m == NULL) { return; }
if (m->actionState == 0) {
switch (++m->actionTimer) {
case 1:
@ -1149,7 +1150,7 @@ s32 act_warp_door_spawn(struct MarioState *m) {
}
} else if (m->usedObj == NULL || (m->usedObj->oAction == 0 || m->usedObj->oAction == 100)) {
if (m->playerIndex == 0) {
if (gNeverEnteredCastle == TRUE && gCurrLevelNum == LEVEL_CASTLE) {
if (gNeverEnteredCastle && gCurrLevelNum == LEVEL_CASTLE) {
set_mario_action(m, ACT_READING_AUTOMATIC_DIALOG, gBehaviorValues.dialogs.CastleEnterDialog);
} else {
set_mario_action(m, ACT_IDLE, 0);
@ -1722,7 +1723,7 @@ s32 act_shocked(struct MarioState *m) {
s32 act_squished(struct MarioState *m) {
if (m == NULL) { return TRUE; }
f32 spaceUnderCeil;
s16 surfAngle;
s32 underSteepSurf = FALSE; // seems to be responsible for setting velocity?
@ -2534,7 +2535,7 @@ static void end_peach_cutscene_dialog_1(struct MarioState *m) {
#endif
sEndPeachAnimation = 6;
break;
#ifdef VERSION_SH
case 111:
#else
@ -2638,7 +2639,7 @@ static void end_peach_cutscene_dialog_2(struct MarioState *m) {
#ifdef VERSION_SH
case 65:
#else
#else
case 45:
#endif
D_8032CBE8 = 1;

View File

@ -1,8 +0,0 @@
#ifndef OPTIONS_MENU_H
#define OPTIONS_MENU_H
void optmenu_draw(void);
void optmenu_draw_prompt(void);
void optmenu_toggle(void);
#endif

View File

@ -309,7 +309,7 @@ void patch_paintings_interpolated(f32 delta) {
if (currPItem == NULL || currPItem == &paintingZero) {
break;
}
}
}
@ -916,7 +916,7 @@ void painting_update_floors(struct Painting *painting) {
if (!consider) {
continue;
}
// floorEntered is true iff currFloor is true and lastFloor is false
// floorEntered is true if currFloor is true and lastFloor is false
// (Mario just entered the floor on this frame)
s8 entered = (painting->ripples.lastFloors[i] ^ painting->ripples.currFloors[i]) & painting->ripples.currFloors[i];
if (entered) {
@ -1023,7 +1023,7 @@ s16 calculate_ripple_at_point(struct Painting *painting, f32 posX, f32 posY) {
// For calculating the highest ripple, ans needs to start extremely low otherwise ripples under 0 won't be counted
s16 ans = multiRippleMode == HIGHEST_RIPPLE ? -32000 : 0;
bool flat = true;
if (multiRippleMode != SINGLE_RIPPLE) {
// If multi ripple mode
for (s32 i = 0; i < MAX_PLAYERS + 1; i++) {
@ -1791,7 +1791,7 @@ Gfx *geo_painting_update(s32 callContext, UNUSED struct GraphNode *node, UNUSED
} else {
gLastPaintingUpdateCounter = gPaintingUpdateCounter;
gPaintingUpdateCounter = gAreaUpdateCounter;
// Store Mario's floor and position
if (gMarioObject) {
find_floor(gMarioObject->oPosX, gMarioObject->oPosY, gMarioObject->oPosZ, &surface);

View File

@ -63,6 +63,8 @@ s8 get_level_course_num(s16 levelNum) {
return (info ? info->courseNum : COURSE_NONE);
}
levelNum = levelNum - 1;
if (INVALID_LEVEL_NUM(levelNum)) {
return COURSE_NONE;
}
@ -392,7 +394,7 @@ void save_file_do_save(s32 fileIndex, s8 forceSave) {
// Write to EEPROM
write_eeprom_savefile(fileIndex, 0, 2);
gSaveFileModified = FALSE;
}
save_main_menu_data();
@ -412,7 +414,7 @@ void save_file_erase(s32 fileIndex) {
void save_file_reload(u8 load_all) {
gSaveFileModified = TRUE;
update_all_mario_stars();
if (load_all == TRUE) {
save_file_load_all(TRUE);
save_file_do_save(gCurrSaveFileNum-1, TRUE);
@ -818,7 +820,7 @@ void check_if_should_set_warp_checkpoint(struct WarpNode *warpNode) {
*/
s32 check_warp_checkpoint(struct WarpNode *warpNode) {
s16 warpCheckpointActive = FALSE;
s16 currCourseNum = get_level_course_num((warpNode->destLevel & 0x7F) - 1);
s16 currCourseNum = get_level_course_num(warpNode->destLevel & 0x7F);
// gSavedCourseNum is only used in this function.
if (gWarpCheckpoint.courseNum != COURSE_NONE && gSavedCourseNum == currCourseNum

View File

@ -25,6 +25,7 @@
#include "pc/network/network.h"
#include "engine/math_util.h"
#include "game/print.h"
#include "game/level_info.h"
/**
* @file star_select.c
@ -278,15 +279,9 @@ void print_act_selector_strings(void) {
#endif
unsigned char starNumbers[] = { TEXT_ZERO };
#ifdef VERSION_EU
u8 **levelNameTbl;
u8 *currLevelName;
u8 **actNameTbl;
#else
u8 **levelNameTbl = segmented_to_virtual(seg2_course_name_table);
u8 **levelNameTbl = get_course_name_table();
u8 *currLevelName = segmented_to_virtual(levelNameTbl[gCurrCourseNum - 1]);
u8 **actNameTbl = segmented_to_virtual(seg2_act_name_table);
#endif
u8 **actNameTbl = get_act_name_table();
u8 *selectedActName;
#ifndef VERSION_EU
s16 lvlNameX;
@ -299,24 +294,6 @@ void print_act_selector_strings(void) {
create_dl_ortho_matrix();
#ifdef VERSION_EU
switch (language) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
levelNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
levelNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
levelNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
currLevelName = segmented_to_virtual(levelNameTbl[gCurrCourseNum - 1]);
#endif
// Print the coin highscore.
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);

View File

@ -13,7 +13,6 @@
#include "dev/chat.h"
#endif
extern bool gIsModerator;
static enum ChatConfirmCommand sConfirming = CCC_NONE;
static u8 sConfirmPlayerIndex = 0;
@ -55,14 +54,15 @@ static void chat_construct_player_message(struct NetworkPlayer* np, char* msg) {
}
bool exec_chat_command(char* command) {
struct NetworkPlayer* npl = &gNetworkPlayers[0];
enum ChatConfirmCommand ccc = sConfirming;
sConfirming = CCC_NONE;
if (ccc != CCC_NONE && strcmp("/confirm", command) == 0) {
if (gNetworkType == NT_SERVER || gIsModerator) {
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
if (!np->connected) return true;
if (gNetworkType == NT_SERVER || npl->moderator) {
if (ccc == CCC_KICK) {
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
if (!np->connected) { return true; }
chat_construct_player_message(np, DLANG(CHAT, KICKING));
if (gNetworkType == NT_SERVER) {
network_send_kick(np->localIndex, EKT_KICKED);
@ -73,10 +73,8 @@ bool exec_chat_command(char* command) {
return true;
}
}
if (gNetworkType == NT_SERVER || gIsModerator) {
if (gNetworkType == NT_SERVER || npl->moderator) {
if (ccc == CCC_BAN) {
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
if (!np->connected) { return true; }
chat_construct_player_message(np, DLANG(CHAT, BANNING));
if (gNetworkType == NT_SERVER) {
network_send_kick(np->localIndex, EKT_BANNED);
@ -89,8 +87,6 @@ bool exec_chat_command(char* command) {
}
}
if (gNetworkType == NT_SERVER && ccc == CCC_PERMBAN) {
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
if (!np->connected) { return true; }
chat_construct_player_message(np, DLANG(CHAT, PERM_BANNING));
network_send_kick(np->localIndex, EKT_BANNED);
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
@ -98,9 +94,8 @@ bool exec_chat_command(char* command) {
return true;
}
if (gNetworkType == NT_SERVER && ccc == CCC_MODERATOR) {
struct NetworkPlayer* np = &gNetworkPlayers[sConfirmPlayerIndex];
if (!np->connected) { return true; }
chat_construct_player_message(np, DLANG(CHAT, ADD_MODERATOR));
np->moderator = true;
network_send_moderator(np->localIndex);
moderator_list_add(gNetworkSystem->get_id_str(np->localIndex), true);
return true;
@ -125,7 +120,7 @@ bool exec_chat_command(char* command) {
}
if (str_starts_with("/kick ", command)) {
if (gNetworkType != NT_SERVER && !gIsModerator) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
return true;
}
@ -148,7 +143,7 @@ bool exec_chat_command(char* command) {
}
if (str_starts_with("/ban ", command)) {
if (gNetworkType != NT_SERVER && !gIsModerator) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
return true;
}
@ -171,7 +166,7 @@ bool exec_chat_command(char* command) {
}
if (str_starts_with("/permban ", command)) {
if (gNetworkType != NT_SERVER && !gIsModerator) {
if (gNetworkType != NT_SERVER && !npl->moderator) {
djui_chat_message_create(DLANG(CHAT, NO_PERMS));
return true;
}
@ -226,15 +221,18 @@ bool exec_chat_command(char* command) {
void display_chat_commands(void) {
djui_chat_message_create(DLANG(CHAT, PLAYERS_DESC));
if (gNetworkType == NT_SERVER || gIsModerator) {
if (gNetworkType == NT_SERVER || gNetworkPlayers[0].moderator) {
djui_chat_message_create(DLANG(CHAT, KICK_DESC));
djui_chat_message_create(DLANG(CHAT, BAN_DESC));
djui_chat_message_create(DLANG(CHAT, PERM_BAN_DESC));
djui_chat_message_create(DLANG(CHAT, MOD_DESC));
if (gNetworkType == NT_SERVER) {
djui_chat_message_create(DLANG(CHAT, PERM_BAN_DESC));
djui_chat_message_create(DLANG(CHAT, MOD_DESC));
}
}
#if defined(DEVELOPMENT)
dev_display_chat_commands();
#endif
if (sConfirming != CCC_NONE) { djui_chat_message_create("/confirm"); }
smlua_display_chat_commands();
}
}

View File

@ -43,7 +43,7 @@ static inline int arg_uint(UNUSED const char *name, const char *value, unsigned
return 1;
}
void parse_cli_opts(int argc, char* argv[]) {
inline void parse_cli_opts(int argc, char* argv[]) {
// Initialize options with false values.
memset(&gCLIOpts, 0, sizeof(gCLIOpts));

View File

@ -113,8 +113,8 @@ unsigned int configCameraPan = 0;
unsigned int configCameraDegrade = 50; // 0 - 100%
bool configCameraInvertX = false;
bool configCameraInvertY = true;
bool configEnableCamera = true;
bool configCameraAnalog = true;
bool configEnableCamera = false;
bool configCameraAnalog = false;
bool configCameraMouse = false;
#endif
bool configSkipIntro = 0;

View File

@ -27,6 +27,7 @@ char gLastRemoteBhv[256] = "";
#include "pc/gfx/gfx_rendering_api.h"
#include "pc/mods/mods.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
typedef struct {
s32 x, y;
@ -659,16 +660,12 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont
// Main loop
while (true) {
#if defined(WAPI_SDL1) || defined(WAPI_SDL2)
gfx_sdl.main_loop(crash_handler_produce_one_frame);
#elif defined(WAPI_DXGI)
gfx_dxgi.main_loop(crash_handler_produce_one_frame);
#endif
WAPI.main_loop(crash_handler_produce_one_frame);
}
exit(0);
}
__attribute__((constructor)) static void init_crash_handler() {
AT_STARTUP static void init_crash_handler() {
#ifdef _WIN32
// Windows
SetUnhandledExceptionFilter(crash_handler);

View File

@ -136,18 +136,18 @@ void discord_activity_update(void) {
}
void discord_activity_update_check(void) {
#ifdef COOPNET
if (sQueuedLobby > 0) {
if (--sQueuedLobby == 0) {
#ifdef COOPNET
gCoopNetDesiredLobby = sQueuedLobbyId;
snprintf(gCoopNetPassword, 64, "%s", sQueuedLobbyPassword);
network_reset_reconnect_and_rehost();
network_set_system(NS_COOPNET);
network_init(NT_CLIENT, false);
djui_panel_join_message_create(NULL);
#endif
}
}
#endif
if (gNetworkType == NT_NONE) { return; }
bool shouldUpdate = false;

View File

@ -3,11 +3,13 @@
#define DJUI_DEFAULT_PANEL_WIDTH (500.0f + (16 * 2.0f))
#define DJUI_PANEL_HEADER_OFFSET (-16)
#define DJUI_PANEL_MOVE_MAX 1.0f
struct DjuiPanel {
struct DjuiBase* base;
struct DjuiPanel* parent;
struct DjuiBase* defaultElementBase;
bool temporary;
void (*on_panel_destroy)(struct DjuiBase*);
};

View File

@ -27294,6 +27294,48 @@ int smlua_func_smlua_audio_utils_reset_all(UNUSED lua_State* L) {
// smlua_collision_utils.h //
/////////////////////////////
int smlua_func_collision_find_ceil(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "collision_find_ceil", 3, top);
return 0;
}
f32 x = smlua_to_number(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "collision_find_ceil"); return 0; }
f32 y = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "collision_find_ceil"); return 0; }
f32 z = smlua_to_number(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "collision_find_ceil"); return 0; }
smlua_push_object(L, LOT_SURFACE, collision_find_ceil(x, y, z));
return 1;
}
int smlua_func_collision_find_floor(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "collision_find_floor", 3, top);
return 0;
}
f32 x = smlua_to_number(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "collision_find_floor"); return 0; }
f32 y = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "collision_find_floor"); return 0; }
f32 z = smlua_to_number(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "collision_find_floor"); return 0; }
smlua_push_object(L, LOT_SURFACE, collision_find_floor(x, y, z));
return 1;
}
int smlua_func_collision_find_surface_on_ray(lua_State* L) {
if (L == NULL) { return 0; }
@ -27475,6 +27517,23 @@ int smlua_func_smlua_level_util_get_info(lua_State* L) {
return 1;
}
int smlua_func_smlua_level_util_get_info_from_course_num(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_level_util_get_info_from_course_num", 1, top);
return 0;
}
u8 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_level_util_get_info_from_course_num"); return 0; }
smlua_push_object(L, LOT_CUSTOMLEVELINFO, smlua_level_util_get_info_from_course_num(courseNum));
return 1;
}
int smlua_func_smlua_level_util_get_info_from_short_name(lua_State* L) {
if (L == NULL) { return 0; }
@ -29844,6 +29903,84 @@ int smlua_func_spawn_sync_object(lua_State* L) {
// smlua_text_utils.h //
////////////////////////
int smlua_func_smlua_text_utils_act_name_get(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_act_name_get", 2, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_act_name_get"); return 0; }
u8 actNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "smlua_text_utils_act_name_get"); return 0; }
lua_pushstring(L, smlua_text_utils_act_name_get(courseNum, actNum));
return 1;
}
int smlua_func_smlua_text_utils_act_name_is_modified(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_act_name_is_modified", 2, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_act_name_is_modified"); return 0; }
u8 actNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "smlua_text_utils_act_name_is_modified"); return 0; }
lua_pushboolean(L, smlua_text_utils_act_name_is_modified(courseNum, actNum));
return 1;
}
int smlua_func_smlua_text_utils_act_name_replace(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_act_name_replace", 3, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_act_name_replace"); return 0; }
u8 actNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "smlua_text_utils_act_name_replace"); return 0; }
const char* name = smlua_to_string(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "smlua_text_utils_act_name_replace"); return 0; }
smlua_text_utils_act_name_replace(courseNum, actNum, name);
return 1;
}
int smlua_func_smlua_text_utils_act_name_reset(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_act_name_reset", 2, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_act_name_reset"); return 0; }
u8 actNum = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "smlua_text_utils_act_name_reset"); return 0; }
smlua_text_utils_act_name_reset(courseNum, actNum);
return 1;
}
int smlua_func_smlua_text_utils_castle_secret_stars_replace(lua_State* L) {
if (L == NULL) { return 0; }
@ -29892,6 +30029,76 @@ int smlua_func_smlua_text_utils_course_acts_replace(lua_State* L) {
return 1;
}
int smlua_func_smlua_text_utils_course_name_get(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_course_name_get", 1, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_course_name_get"); return 0; }
lua_pushstring(L, smlua_text_utils_course_name_get(courseNum));
return 1;
}
int smlua_func_smlua_text_utils_course_name_mod_index(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_course_name_mod_index", 1, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_course_name_mod_index"); return 0; }
lua_pushinteger(L, smlua_text_utils_course_name_mod_index(courseNum));
return 1;
}
int smlua_func_smlua_text_utils_course_name_replace(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_course_name_replace", 2, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_course_name_replace"); return 0; }
const char* name = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "smlua_text_utils_course_name_replace"); return 0; }
smlua_text_utils_course_name_replace(courseNum, name);
return 1;
}
int smlua_func_smlua_text_utils_course_name_reset(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_course_name_reset", 1, top);
return 0;
}
s16 courseNum = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "smlua_text_utils_course_name_reset"); return 0; }
smlua_text_utils_course_name_reset(courseNum);
return 1;
}
int smlua_func_smlua_text_utils_dialog_replace(lua_State* L) {
if (L == NULL) { return 0; }
@ -29953,21 +30160,6 @@ int smlua_func_smlua_text_utils_get_language(UNUSED lua_State* L) {
return 1;
}
int smlua_func_smlua_text_utils_reset_all(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "smlua_text_utils_reset_all", 0, top);
return 0;
}
smlua_text_utils_reset_all();
return 1;
}
int smlua_func_smlua_text_utils_secret_star_replace(lua_State* L) {
if (L == NULL) { return 0; }
@ -32135,6 +32327,8 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "smlua_audio_utils_reset_all", smlua_func_smlua_audio_utils_reset_all);
// smlua_collision_utils.h
smlua_bind_function(L, "collision_find_ceil", smlua_func_collision_find_ceil);
smlua_bind_function(L, "collision_find_floor", smlua_func_collision_find_floor);
smlua_bind_function(L, "collision_find_surface_on_ray", smlua_func_collision_find_surface_on_ray);
smlua_bind_function(L, "collision_get_temp_wall_collision_data", smlua_func_collision_get_temp_wall_collision_data);
smlua_bind_function(L, "get_water_surface_pseudo_floor", smlua_func_get_water_surface_pseudo_floor);
@ -32148,6 +32342,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "level_register", smlua_func_level_register);
smlua_bind_function(L, "smlua_level_util_change_area", smlua_func_smlua_level_util_change_area);
smlua_bind_function(L, "smlua_level_util_get_info", smlua_func_smlua_level_util_get_info);
smlua_bind_function(L, "smlua_level_util_get_info_from_course_num", smlua_func_smlua_level_util_get_info_from_course_num);
smlua_bind_function(L, "smlua_level_util_get_info_from_short_name", smlua_func_smlua_level_util_get_info_from_short_name);
smlua_bind_function(L, "warp_exit_level", smlua_func_warp_exit_level);
smlua_bind_function(L, "warp_restart_level", smlua_func_warp_restart_level);
@ -32291,12 +32486,19 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "spawn_sync_object", smlua_func_spawn_sync_object);
// smlua_text_utils.h
smlua_bind_function(L, "smlua_text_utils_act_name_get", smlua_func_smlua_text_utils_act_name_get);
smlua_bind_function(L, "smlua_text_utils_act_name_is_modified", smlua_func_smlua_text_utils_act_name_is_modified);
smlua_bind_function(L, "smlua_text_utils_act_name_replace", smlua_func_smlua_text_utils_act_name_replace);
smlua_bind_function(L, "smlua_text_utils_act_name_reset", smlua_func_smlua_text_utils_act_name_reset);
smlua_bind_function(L, "smlua_text_utils_castle_secret_stars_replace", smlua_func_smlua_text_utils_castle_secret_stars_replace);
smlua_bind_function(L, "smlua_text_utils_course_acts_replace", smlua_func_smlua_text_utils_course_acts_replace);
smlua_bind_function(L, "smlua_text_utils_course_name_get", smlua_func_smlua_text_utils_course_name_get);
smlua_bind_function(L, "smlua_text_utils_course_name_mod_index", smlua_func_smlua_text_utils_course_name_mod_index);
smlua_bind_function(L, "smlua_text_utils_course_name_replace", smlua_func_smlua_text_utils_course_name_replace);
smlua_bind_function(L, "smlua_text_utils_course_name_reset", smlua_func_smlua_text_utils_course_name_reset);
smlua_bind_function(L, "smlua_text_utils_dialog_replace", smlua_func_smlua_text_utils_dialog_replace);
smlua_bind_function(L, "smlua_text_utils_extra_text_replace", smlua_func_smlua_text_utils_extra_text_replace);
smlua_bind_function(L, "smlua_text_utils_get_language", smlua_func_smlua_text_utils_get_language);
smlua_bind_function(L, "smlua_text_utils_reset_all", smlua_func_smlua_text_utils_reset_all);
smlua_bind_function(L, "smlua_text_utils_secret_star_replace", smlua_func_smlua_text_utils_secret_star_replace);
// sound_init.h

View File

@ -417,13 +417,15 @@ void smlua_push_object(lua_State* L, u16 lot, void* p) {
lua_pushnil(L);
return;
}
u64 pointer = (uintptr_t) p;
// add to allowlist
smlua_cobject_allowlist_add(lot, (u64)(intptr_t)p);
smlua_cobject_allowlist_add(lot, pointer);
// get a cobject from a function
lua_getglobal(L, "_NewCObject"); // Get the function by its global name
lua_pushinteger(L, lot);
lua_pushinteger(L, (u64)(intptr_t)p);
lua_pushinteger(L, pointer);
if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
LOG_ERROR("Error calling Lua function: %s\n", lua_tostring(L, -1));
@ -436,12 +438,13 @@ void smlua_push_pointer(lua_State* L, u16 lvt, void* p) {
return;
}
smlua_cpointer_allowlist_add(lvt, (u64)(intptr_t)p);
u64 pointer = (uintptr_t) p;
smlua_cpointer_allowlist_add(lvt, pointer);
// get a cpointer from a function
lua_getglobal(L, "_NewCPointer"); // Get the function by its global name
lua_pushinteger(L, lvt);
lua_pushinteger(L, (u64)(intptr_t)p);
lua_pushinteger(L, pointer);
if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
LOG_ERROR("Error calling Lua function: %s\n", lua_tostring(L, -1));
}
@ -550,7 +553,7 @@ s64 smlua_get_integer_mod_variable(u16 modIndex, const char* variable) {
LOG_ERROR("Could not find mod list entry for modIndex: %u", modIndex);
return 0;
}
u8 prevSuppress = gSmLuaSuppressErrors;
int prevTop = lua_gettop(L);
@ -601,7 +604,7 @@ LuaFunction smlua_get_function_mod_variable(u16 modIndex, const char *variable)
LOG_ERROR("Could not find mod list entry for modIndex: %u", modIndex);
return 0;
}
u8 prevSuppress = gSmLuaSuppressErrors;
int prevTop = lua_gettop(L);

View File

@ -1,6 +1,7 @@
#include "types.h"
#include "src/engine/surface_collision.h"
#include "include/surface_terrains.h"
#include "game/mario_step.h"
#include "pc/lua/smlua.h"
@ -164,6 +165,18 @@ struct RayIntersectionInfo* collision_find_surface_on_ray(f32 startX, f32 startY
return &info;
}
struct Surface* collision_find_floor(f32 x, f32 y, f32 z) {
static struct Surface *surface;
find_floor(x, y, z, &surface);
return surface;
}
struct Surface* collision_find_ceil(f32 x, f32 y, f32 z) {
static struct Surface *surface;
find_ceil(x, y, z, &surface);
return surface;
}
struct Surface* get_water_surface_pseudo_floor(void) {
return &gWaterSurfacePseudoFloor;
}

View File

@ -116,6 +116,10 @@ extern struct GlobalObjectCollisionData gGlobalObjectCollisionData;
struct RayIntersectionInfo* collision_find_surface_on_ray(f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ);
struct Surface* collision_find_floor(f32 x, f32 y, f32 z);
struct Surface* collision_find_ceil(f32 x, f32 y, f32 z);
struct Surface* get_water_surface_pseudo_floor(void);
Collision* smlua_collision_util_get(const char* name);

View File

@ -73,6 +73,17 @@ static struct CustomLevelInfo* smlua_level_util_get_info_from_script(char* scrip
return NULL;
}
struct CustomLevelInfo* smlua_level_util_get_info_from_course_num(u8 courseNum) {
struct CustomLevelInfo* node = sCustomLevelHead;
while (node != NULL) {
if (node->courseNum == courseNum) {
return node;
}
node = node->next;
}
return NULL;
}
s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullName, const char* shortName, u32 acousticReach, u32 echoLevel1, u32 echoLevel2, u32 echoLevel3) {
// validate params
if (scriptEntryName == NULL) {

View File

@ -21,7 +21,8 @@ struct CustomLevelInfo {
void smlua_level_util_reset(void);
void smlua_level_util_change_area(s32 areaIndex);
struct CustomLevelInfo* smlua_level_util_get_info(s16 levelNum);
struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(const char* shortName);
struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(char* shortName);
struct CustomLevelInfo* smlua_level_util_get_info_from_course_num(u8 courseNum);
s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullName, const char* shortName, u32 acousticReach, u32 echoLevel1, u32 echoLevel2, u32 echoLevel3);
bool level_is_vanilla_level(s16 levelNum);
bool warp_to_warpnode(s32 aLevel, s32 aArea, s32 aAct, s32 aWarpId);

View File

@ -5,6 +5,11 @@
#include "game/ingame_menu.h"
#include "game/save_file.h"
#include "game/segment2.h"
#include "game/level_info.h"
#include "pc/pc_main.h"
#include "../smlua.h"
#include "smlua_level_utils.h"
#include "smlua_text_utils.h"
#ifdef VERSION_EU
extern s32 gInGameLanguage;
@ -15,6 +20,42 @@ static bool sReplacedDialog[DIALOG_COUNT] = { 0 };
static bool sReplacedCourseName[COURSE_COUNT+2] = { 0 };
static bool sReplacedActName[(COURSE_RR+2)*6] = { 0 };
#define INVALID_COURSE_NUM(courseNum) (smlua_level_util_get_info_from_course_num(courseNum) == NULL && !COURSE_IS_VALID_COURSE(courseNum))
void convert_string_sm64_to_ascii(char *strAscii, const u8 *str64);
struct CourseName *gReplacedActNameTable[COURSE_COUNT];
// Save all vanilla act names and course names
AT_STARTUP static void smlua_text_utils_init() {
void **actNameTbl = get_act_name_table();
void **courseNameTbl = get_course_name_table();
char courseBuffer[50];
char actBuffer[50];
for (s16 courseNum = 0; courseNum < COURSE_COUNT; courseNum++) {
const u8 *courseName = segmented_to_virtual(courseNameTbl[courseNum]);
convert_string_sm64_to_ascii(courseBuffer, courseName);
gReplacedActNameTable[courseNum] = malloc(sizeof(struct CourseName));
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->name, 50, "%s", courseBuffer);
snprintf(courseActNames->orig, 50, "%s", courseBuffer);
courseActNames->modIndex = -1;
// Individual acts
if (COURSE_IS_MAIN_COURSE(courseNum)) {
courseActNames->actName = calloc(6, sizeof(struct ActName));
for (s16 actNum = 0; actNum < 6; actNum++) {
const u8 *starName = segmented_to_virtual(actNameTbl[courseNum * 6 + actNum]);
convert_string_sm64_to_ascii(actBuffer, starName);
snprintf(courseActNames->actName[actNum].name, 50, "%s", actBuffer);
snprintf(courseActNames->actName[actNum].orig, 50, "%s", actBuffer);
courseActNames->actName[actNum].isModified = false;
}
}
}
}
static u8* smlua_text_utils_convert(const char* str) {
s32 len = strlen(str);
u8* dialogStr = calloc(len + 2, sizeof(u8));
@ -29,7 +70,7 @@ void smlua_text_utils_reset_all(void) {
void **dialogTableOrg = NULL;
void **actNameTblOrg = NULL;
void **courseNameTblOrg = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
@ -87,13 +128,27 @@ void smlua_text_utils_reset_all(void) {
actNameTbl[i] = segmented_to_virtual(actNameTblOrg[i]);
sReplacedActName[i] = false;
}
for (s32 courseNum = 0; courseNum < COURSE_COUNT; courseNum++) {
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->name, 50, "%s", courseActNames->orig);
courseActNames->modIndex = -1;
// Individual acts
if (COURSE_IS_MAIN_COURSE(courseNum)) {
for (s16 actNum = 0; actNum < 6; actNum++) {
snprintf(courseActNames->actName[actNum].name, 50, "%s", courseActNames->actName[actNum].orig);
courseActNames->actName[actNum].isModified = false;
}
}
}
}
void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused, s8 linesPerBox, s16 leftOffset, s16 width, const char* str) {
if (dialogId >= DIALOG_COUNT) { return; }
void **dialogTable = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
@ -124,75 +179,88 @@ void smlua_text_utils_dialog_replace(enum DialogId dialogId, UNUSED u32 unused,
sReplacedDialog[dialogId] = true;
}
#define REPLACE_ACT_NAME(i) \
snprintf(courseActNames->actName[i-1].name, 256, "%s", act##i); \
courseActNames->actName[i-1].isModified = true; \
void smlua_text_utils_course_acts_replace(s16 courseNum, const char* courseName, const char* act1, const char* act2, const char* act3, const char* act4, const char* act5, const char* act6) {
if (courseNum <= 0 || courseNum > COURSE_RR) { return; }
s16 courseOffset = courseNum - 1;
void **actNameTbl = NULL;
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#else
actNameTbl = segmented_to_virtual(seg2_act_name_table);
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->name, 256, "%s", courseName + 3);
courseActNames->modIndex = gLuaActiveMod->index;
// replace course name
if (sReplacedCourseName[courseOffset]) {
free(courseNameTbl[courseOffset]);
}
courseNameTbl[courseOffset] = smlua_text_utils_convert(courseName);
sReplacedCourseName[courseOffset] = true;
REPLACE_ACT_NAME(1);
REPLACE_ACT_NAME(2);
REPLACE_ACT_NAME(3);
REPLACE_ACT_NAME(4);
REPLACE_ACT_NAME(5);
REPLACE_ACT_NAME(6);
// replace act names
const char* newActs[] = { act1, act2, act3, act4, act5, act6 };
for (s32 i = 0; i < 6; i++) {
s32 index = (courseOffset * 6 + i);
LOG_INFO("%d (%s) replacing act names 1-6 of course %d, (%s), act 1: %s", courseActNames->modIndex, gLuaActiveMod->name, courseNum, courseName, act1);
}
if (sReplacedActName[index]) {
free(actNameTbl[index]);
}
void smlua_text_utils_course_name_replace(s16 courseNum, const char* name) {
if (INVALID_COURSE_NUM(courseNum)) { return; }
actNameTbl[index] = smlua_text_utils_convert(newActs[i]);
sReplacedActName[index] = true;
}
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->name, 256, "%s", name);
courseActNames->modIndex = gLuaActiveMod->index;
}
const char* smlua_text_utils_course_name_get(s16 courseNum) {
if (INVALID_COURSE_NUM(courseNum)) { return NULL; }
return gReplacedActNameTable[courseNum]->name;
}
s32 smlua_text_utils_course_name_mod_index(s16 courseNum) {
if (INVALID_COURSE_NUM(courseNum)) { return -1; }
return gReplacedActNameTable[courseNum]->modIndex;
}
void smlua_text_utils_course_name_reset(s16 courseNum) {
if (INVALID_COURSE_NUM(courseNum)) { return; }
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->name, 50, "%s", courseActNames->orig);
courseActNames->modIndex = -1;
}
void smlua_text_utils_act_name_replace(s16 courseNum, u8 actNum, const char* name) {
if (INVALID_COURSE_NUM(courseNum) || actNum > 7) { return; }
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->actName[actNum].name, 256, "%s", name);
courseActNames->actName[actNum].isModified = true;
}
const char* smlua_text_utils_act_name_get(s16 courseNum, u8 actNum) {
if (INVALID_COURSE_NUM(courseNum) || actNum > 7) { return NULL; }
return gReplacedActNameTable[courseNum]->actName[actNum].name;
}
bool smlua_text_utils_act_name_is_modified(s16 courseNum, u8 actNum) {
if (INVALID_COURSE_NUM(courseNum) || actNum > 7) { return false; }
return gReplacedActNameTable[courseNum]->actName[actNum].isModified;
}
void smlua_text_utils_act_name_reset(s16 courseNum, u8 actNum) {
if (INVALID_COURSE_NUM(courseNum) || actNum > 7) { return; }
struct CourseName* courseActNames = gReplacedActNameTable[courseNum];
snprintf(courseActNames->actName[actNum].name, 50, "%s", courseActNames->actName[actNum].orig);
courseActNames->actName[actNum].isModified = false;
}
void smlua_text_utils_secret_star_replace(s16 courseNum, const char* courseName) {
if (courseNum <= COURSE_RR || courseNum > COURSE_COUNT) { return; }
s16 courseOffset = courseNum - 1;
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#else
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
void **courseNameTbl = get_course_name_table();
if (sReplacedCourseName[courseOffset]) {
free(courseNameTbl[courseOffset]);
@ -204,24 +272,8 @@ void smlua_text_utils_secret_star_replace(s16 courseNum, const char* courseName)
void smlua_text_utils_castle_secret_stars_replace(const char* name) {
s16 courseOffset = COURSE_COUNT;
void **courseNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
courseNameTbl = segmented_to_virtual(course_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
courseNameTbl = segmented_to_virtual(course_name_table_eu_de);
break;
}
#else
courseNameTbl = segmented_to_virtual(seg2_course_name_table);
#endif
void **courseNameTbl = get_course_name_table();
if (sReplacedCourseName[courseOffset]) {
free(courseNameTbl[courseOffset]);
@ -234,24 +286,8 @@ void smlua_text_utils_castle_secret_stars_replace(const char* name) {
void smlua_text_utils_extra_text_replace(s16 index, const char* text) {
if (index < 0 || index > 6) { return; }
index = (COURSE_RR * 6 + index);
void **actNameTbl = NULL;
#ifdef VERSION_EU
switch (gInGameLanguage) {
case LANGUAGE_ENGLISH:
actNameTbl = segmented_to_virtual(act_name_table_eu_en);
break;
case LANGUAGE_FRENCH:
actNameTbl = segmented_to_virtual(act_name_table_eu_fr);
break;
case LANGUAGE_GERMAN:
actNameTbl = segmented_to_virtual(act_name_table_eu_de);
break;
}
#else
actNameTbl = segmented_to_virtual(seg2_act_name_table);
#endif
void **actNameTbl = get_act_name_table();
if (sReplacedActName[index]) {
free(actNameTbl[index]);
@ -263,4 +299,4 @@ void smlua_text_utils_extra_text_replace(s16 index, const char* text) {
const char* smlua_text_utils_get_language(void) {
return configLanguage;
}
}

View File

@ -4,10 +4,31 @@
#include "types.h"
#include "dialog_ids.h"
struct ActName {
char name[256];
char orig[256];
bool isModified;
};
struct CourseName {
struct ActName *actName;
char name[256];
char orig[256];
s32 modIndex;
};
void smlua_text_utils_reset_all(void);
void smlua_text_utils_dialog_replace(enum DialogId dialogId, u32 unused, s8 linesPerBox, s16 leftOffset, s16 width, const char* str);
void smlua_text_utils_course_acts_replace(s16 courseNum, const char* courseName, const char* act1, const char* act2, const char* act3, const char* act4, const char* act5, const char* act6);
void smlua_text_utils_secret_star_replace(s16 courseNum, const char* courseName);
void smlua_text_utils_course_name_replace(s16 courseNum, const char* name);
const char* smlua_text_utils_course_name_get(s16 courseNum);
s32 smlua_text_utils_course_name_mod_index(s16 courseNum);
void smlua_text_utils_course_name_reset(s16 courseNum);
void smlua_text_utils_act_name_replace(s16 courseNum, u8 actNum, const char* name);
const char* smlua_text_utils_act_name_get(s16 courseNum, u8 actNum);
bool smlua_text_utils_act_name_is_modified(s16 courseNum, u8 actNum);
void smlua_text_utils_act_name_reset(s16 courseNum, u8 actNum);
void smlua_text_utils_castle_secret_stars_replace(const char* name);
void smlua_text_utils_extra_text_replace(s16 index, const char* text);
const char* smlua_text_utils_get_language(void);

View File

@ -4,6 +4,7 @@
#include "mod_cache.h"
#include "data/dynos.c.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#define MAX_SESSION_CHARS 7

View File

@ -32,9 +32,7 @@ void moderator_list_add(char* address, bool perm) {
gModerator = malloc(sizeof(bool) * gModeratorCount);
} else {
gModeratorAddresses = realloc(gModeratorAddresses, sizeof(char*) * gModeratorCount);
assert(gModeratorAddresses != NULL);
gModerator = realloc(gModerator, sizeof(bool) * gModeratorCount);
assert(gModerator != NULL);
}
if (gModeratorAddresses == NULL) {
LOG_ERROR("Failed to allocate gModeratorAddresses");

View File

@ -373,6 +373,7 @@ void network_send(struct Packet* p) {
}
void network_receive(u8 localIndex, void* addr, u8* data, u16 dataLength) {
// receive packet
struct Packet p = {
.localIndex = localIndex,
@ -681,9 +682,6 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
extern s16 gMenuMode;
gMenuMode = -1;
extern bool gIsModerator;
gIsModerator = false;
djui_panel_shutdown();
extern bool gDjuiInMainMenu;
if (!gDjuiInMainMenu) {

View File

@ -25,6 +25,7 @@ struct NetworkPlayer {
u8 type;
u8 localIndex;
u8 globalIndex;
bool moderator;
f32 lastReceived;
f32 lastSent;
f32 lastPingSent;

View File

@ -27,8 +27,7 @@ bool network_is_server(void) {
}
bool network_is_moderator(void) {
extern bool gIsModerator;
return gIsModerator;
return gNetworkPlayers[0].moderator;
}
u8* network_get_player_text_color(u8 localIndex) {

View File

@ -100,7 +100,7 @@ void network_receive_chat(struct Packet* p) {
// add the message
djui_chat_message_create_from(globalIndex, remoteMessage);
if (gNetworkSystem && gNetworkSystem->get_id_str && np) {
if (gNetworkSystem && gNetworkSystem->get_id_str && np->connected && strlen(np->name) > 0) {
LOG_CONSOLE("[%s] %s: %s", gNetworkSystem->get_id_str(np->localIndex), np->name, remoteMessage);
LOG_INFO("[%s] %s: %s", gNetworkSystem->get_id_str(np->localIndex), np->name, remoteMessage);
} else {

View File

@ -4,53 +4,55 @@
#include "pc/djui/djui_chat_message.h"
#include "pc/network/ban_list.h"
#include "pc/network/moderator_list.h"
bool gIsModerator = false;
#include "pc/debuglog.h"
void network_send_chat_command(u8 globalIndex, enum ChatConfirmCommand ccc) {
if (gIsModerator) {
u8 cccType = ccc;
struct Packet p = { 0 };
packet_init(&p, PACKET_COMMAND, false, PLMT_NONE);
packet_write(&p, &globalIndex, sizeof(u8));
packet_write(&p, &cccType, sizeof(u8));
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
if (!gNetworkPlayers[0].moderator) return;
u8 cccType = ccc; struct Packet p = { 0 };
LOG_INFO("sending chat command to host with type: %d", cccType);
packet_init(&p, PACKET_COMMAND, false, PLMT_NONE);
packet_write(&p, &globalIndex, sizeof(u8));
packet_write(&p, &cccType, sizeof(u8));
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
void network_receive_chat_command(struct Packet *p) {
if (!moderator_list_contains(gNetworkSystem->get_id_str(p->localIndex))) {
if (gNetworkType != NT_SERVER) {
LOG_ERROR("recieved chat command as non server");
return;
}
enum ChatConfirmCommand CCC;
u8 player;
if (!moderator_list_contains(gNetworkSystem->get_id_str(p->localIndex))) {
LOG_ERROR("recieved moderator command from non moderator");
return;
}
u8 CCC; u8 player;
packet_read(p, &player, sizeof(u8));
packet_read(p, &CCC, sizeof(u8));
if (gNetworkType == NT_SERVER && CCC == CCC_KICK) {
struct NetworkPlayer *np = &gNetworkPlayers[player];
if (!np->connected) {
return;
}
network_send_kick(np->localIndex, EKT_KICKED);
network_player_disconnected(np->localIndex);
char message[256] = { 0 };
snprintf(message, 256, "\\#fff982\\Kicked '%s%s\\#fff982\\'!",
network_get_player_text_color_string(np->localIndex), np->name);
djui_chat_message_create(message);
if (CCC != CCC_KICK && CCC != CCC_BAN) {
LOG_ERROR("recieved an invalid chat command: %d", CCC);
return;
}
if (gNetworkType == NT_SERVER && CCC == CCC_BAN) {
struct NetworkPlayer *np = &gNetworkPlayers[player];
if (!np->connected) {
return;
}
struct NetworkPlayer *np = &gNetworkPlayers[player];
if (!np->connected) {
LOG_ERROR("recieved player that isn't connected");
return;
}
char message[256] = { 0 };
if (CCC == CCC_KICK) {
network_send_kick(np->localIndex, EKT_KICKED);
snprintf(message, 256, "\\#fff982\\Kicked '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name);
}
if (CCC == CCC_BAN) {
network_send_kick(np->localIndex, EKT_BANNED);
ban_list_add(gNetworkSystem->get_id_str(np->localIndex), false);
network_player_disconnected(np->localIndex);
char message[256] = { 0 };
snprintf(message, 256, "\\#fff982\\Banned '%s%s\\#fff982\\'!",
network_get_player_text_color_string(np->localIndex), np->name);
djui_chat_message_create(message);
snprintf(message, 256, "\\#fff982\\Banned '%s%s\\#fff982\\'!", network_get_player_text_color_string(np->localIndex), np->name);
}
network_player_disconnected(np->localIndex);
djui_chat_message_create(message);
}
void network_send_moderator(u8 localIndex) {
@ -60,10 +62,7 @@ void network_send_moderator(u8 localIndex) {
}
void network_receive_moderator(struct Packet *p) {
if ((gIsModerator) || (network_player_any_connected() && gNetworkPlayers[p->localIndex].type != NPT_SERVER)) {
return;
}
gIsModerator = true;
if (gNetworkPlayers[0].moderator || (network_player_any_connected() && gNetworkPlayers[p->localIndex].type != NPT_SERVER)) return;
gNetworkPlayers[0].moderator = true;
djui_chat_message_create(DLANG(CHAT, MOD_GRANTED));
}
}

View File

@ -468,7 +468,9 @@ void network_update_objects(void) {
// check for stale sync object
if (so->o->oSyncID != so->id) {
LOG_ERROR("sync id mismatch: %d vs %d (behavior %d)", so->o->oSyncID, so->id, get_id_from_behavior(so->o->behavior));
enum BehaviorId bhvId = get_id_from_behavior(so->o->behavior);
const char* bhvName = get_behavior_name_from_id(bhvId);
LOG_ERROR("sync id mismatch: %d vs %d (behavior %s, %d)", so->o->oSyncID, so->id, bhvName != NULL ? bhvName : "NULL", bhvId);
sync_object_forget(so->id);
continue;
}

View File

@ -12,16 +12,6 @@
#include "network/network.h"
#include "lua/smlua.h"
#include "gfx/gfx_pc.h"
#include "gfx/gfx_opengl.h"
#include "gfx/gfx_direct3d11.h"
#include "gfx/gfx_direct3d12.h"
#include "gfx/gfx_dxgi.h"
#include "gfx/gfx_sdl.h"
#include "gfx/gfx_dummy.h"
#include "audio/audio_api.h"
#include "audio/audio_sdl.h"
#include "audio/audio_null.h"
@ -87,25 +77,22 @@ static f64 sLastFrameTimeStart;
static f32 sAvgFrames = 1;
static f32 sAvgFps = 0;
bool gGameInited = false;
bool gGfxInited = false;
static struct AudioAPI *audio_api;
struct GfxWindowManagerAPI *wm_api;
static struct GfxRenderingAPI *rendering_api;
struct GfxWindowManagerAPI *wm_api = &WAPI;
extern void gfx_run(Gfx *commands);
extern void thread5_game_loop(void *arg);
extern void create_next_audio_buffer(s16 *samples, u32 num_samples);
void game_loop_one_iteration(void);
void dispatch_audio_sptask(UNUSED struct SPTask *spTask) {
}
void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) {
}
static bool inited = false;
void dispatch_audio_sptask(UNUSED struct SPTask *spTask) {}
void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) {}
void send_display_list(struct SPTask *spTask) {
if (!inited) return;
if (!gGameInited) { return; }
gfx_run((Gfx *)spTask->task.t.data_ptr);
}
@ -117,17 +104,29 @@ void send_display_list(struct SPTask *spTask) {
#define SAMPLES_LOW 528
#endif
extern void patch_mtx_before(void);
extern void patch_screen_transition_before(void);
extern void patch_title_screen_before(void);
extern void patch_dialog_before(void);
extern void patch_hud_before(void);
extern void patch_paintings_before(void);
extern void patch_bubble_particles_before(void);
extern void patch_snow_particles_before(void);
extern void patch_djui_before(void);
extern void patch_djui_hud_before(void);
extern void patch_mtx_interpolated(f32 delta);
extern void patch_screen_transition_interpolated(f32 delta);
extern void patch_title_screen_interpolated(f32 delta);
extern void patch_dialog_interpolated(f32 delta);
extern void patch_hud_interpolated(f32 delta);
extern void patch_paintings_interpolated(f32 delta);
extern void patch_bubble_particles_interpolated(f32 delta);
extern void patch_snow_particles_interpolated(f32 delta);
extern void patch_djui_interpolated(f32 delta);
extern void patch_djui_hud(f32 delta);
static void patch_interpolations_before(void) {
extern void patch_mtx_before(void);
extern void patch_screen_transition_before(void);
extern void patch_title_screen_before(void);
extern void patch_dialog_before(void);
extern void patch_hud_before(void);
extern void patch_paintings_before(void);
extern void patch_bubble_particles_before(void);
extern void patch_snow_particles_before(void);
extern void patch_djui_before(void);
extern void patch_djui_hud_before(void);
patch_mtx_before();
patch_screen_transition_before();
patch_title_screen_before();
@ -141,16 +140,6 @@ static void patch_interpolations_before(void) {
}
static inline void patch_interpolations(f32 delta) {
extern void patch_mtx_interpolated(f32 delta);
extern void patch_screen_transition_interpolated(f32 delta);
extern void patch_title_screen_interpolated(f32 delta);
extern void patch_dialog_interpolated(f32 delta);
extern void patch_hud_interpolated(f32 delta);
extern void patch_paintings_interpolated(f32 delta);
extern void patch_bubble_particles_interpolated(f32 delta);
extern void patch_snow_particles_interpolated(f32 delta);
extern void patch_djui_interpolated(f32 delta);
extern void patch_djui_hud(f32 delta);
patch_mtx_interpolated(delta);
patch_screen_transition_interpolated(delta);
patch_title_screen_interpolated(delta);
@ -163,19 +152,17 @@ static inline void patch_interpolations(f32 delta) {
patch_djui_hud(delta);
}
void produce_interpolation_frames_and_delay(void) {
u64 frames = 0;
f64 curTime = clock_elapsed_f64();
gRenderingInterpolated = true;
// sanity check target time to deal with hangs and such
f64 curTime = clock_elapsed_f64();
if (fabs(sFrameTargetTime - curTime) > 1) {
sFrameTargetTime = curTime - 0.01f;
}
if (fabs(sFrameTargetTime - curTime) > 1) { sFrameTargetTime = curTime - 0.01f; }
u64 frames = 0;
// interpolate and render
while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) {
// interpolate and render
gfx_start_frame();
f32 delta = MIN((curTime - sFrameTimeStart) / (sFrameTargetTime - sFrameTimeStart), 1);
gRenderingDelta = delta;
@ -185,12 +172,12 @@ void produce_interpolation_frames_and_delay(void) {
// delay
if (!configUncappedFramerate) {
f64 targetDelta = 1.0 / (f64)configFrameLimit;
f64 targetDelta = 1.0 / (f64) configFrameLimit;
f64 now = clock_elapsed_f64();
f64 actualDelta = now - curTime;
if (actualDelta < targetDelta) {
f64 delay = ((targetDelta - actualDelta) * 1000.0);
wm_api->delay((u32)delay);
WAPI.delay((u32) delay);
}
}
@ -207,50 +194,35 @@ void produce_interpolation_frames_and_delay(void) {
//printf(">>> fpt: %llu, fps: %f :: %f\n", frames, sAvgFps, fps);
}
void produce_one_frame(void) {
CTX_BEGIN(CTX_NETWORK);
network_update();
CTX_END(CTX_NETWORK);
inline static void buffer_audio(void) {
int samples_left = audio_api->buffered();
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
s16 audio_buffer[SAMPLES_HIGH * 2 * 2];
for (s32 i = 0; i < 2; i++) {
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
}
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
}
CTX_BEGIN(CTX_INTERP);
patch_interpolations_before();
CTX_END(CTX_INTERP);
void produce_one_frame(void) {
CTX_EXTENT(CTX_NETWORK, network_update);
CTX_EXTENT(CTX_INTERP, patch_interpolations_before);
const f32 master_mod = (f32)configMasterVolume / 127.0f;
set_sequence_player_volume(SEQ_PLAYER_LEVEL, (f32)configMusicVolume / 127.0f * master_mod);
set_sequence_player_volume(SEQ_PLAYER_SFX, (f32)configSfxVolume / 127.0f * master_mod);
set_sequence_player_volume(SEQ_PLAYER_ENV, (f32)configEnvVolume / 127.0f * master_mod);
CTX_BEGIN(CTX_GAME_LOOP);
game_loop_one_iteration();
CTX_END(CTX_GAME_LOOP);
CTX_EXTENT(CTX_GAME_LOOP, game_loop_one_iteration);
CTX_BEGIN(CTX_SMLUA);
smlua_update();
CTX_END(CTX_SMLUA);
CTX_EXTENT(CTX_SMLUA, smlua_update);
thread6_rumble_loop(NULL);
CTX_BEGIN(CTX_AUDIO);
int samples_left = audio_api->buffered();
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
//printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
s16 audio_buffer[SAMPLES_HIGH * 2 * 2];
for (s32 i = 0; i < 2; i++) {
/*if (audio_cnt-- == 0) {
audio_cnt = 2;
}
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
}
//printf("Audio samples before submitting: %d\n", audio_api->buffered());
CTX_EXTENT(CTX_AUDIO, buffer_audio);
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
CTX_END(CTX_AUDIO);
CTX_BEGIN(CTX_RENDER);
produce_interpolation_frames_and_delay();
CTX_END(CTX_RENDER);
CTX_EXTENT(CTX_RENDER, produce_interpolation_frames_and_delay);
}
void audio_shutdown(void) {
@ -270,7 +242,7 @@ void game_deinit(void) {
network_shutdown(true, true, false, false);
smlua_shutdown();
mods_shutdown();
inited = false;
gGameInited = false;
}
void game_exit(void) {
@ -279,10 +251,6 @@ void game_exit(void) {
exit(0);
}
void inthand(UNUSED int signum) {
game_exit();
}
void main_func(void) {
const char *gamedir = gCLIOpts.GameDir[0] ? gCLIOpts.GameDir : FS_BASEDIR;
const char *userpath = gCLIOpts.SavePath[0] ? gCLIOpts.SavePath : sys_user_path();
@ -315,62 +283,30 @@ void main_func(void) {
if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; }
if (gCLIOpts.FullScreen == 1)
configWindow.fullscreen = true;
else if (gCLIOpts.FullScreen == 2)
configWindow.fullscreen = false;
if (gCLIOpts.FullScreen == 1) { configWindow.fullscreen = true; }
else if (gCLIOpts.FullScreen == 2) { configWindow.fullscreen = false; }
#if defined(WAPI_SDL1) || defined(WAPI_SDL2)
wm_api = &gfx_sdl;
#elif defined(WAPI_DXGI)
wm_api = &gfx_dxgi;
#elif defined(WAPI_DUMMY)
wm_api = &gfx_dummy_wm_api;
#else
#error No window API!
#endif
#if defined(RAPI_D3D11)
rendering_api = &gfx_direct3d11_api;
# define RAPI_NAME "DirectX 11"
#elif defined(RAPI_D3D12)
rendering_api = &gfx_direct3d12_api;
# define RAPI_NAME "DirectX 12"
#elif defined(RAPI_GL) || defined(RAPI_GL_LEGACY)
rendering_api = &gfx_opengl_api;
# ifdef USE_GLES
# define RAPI_NAME "OpenGL ES"
# else
# define RAPI_NAME "OpenGL"
# endif
#elif defined(RAPI_DUMMY)
rendering_api = &gfx_dummy_renderer_api;
#else
#error No rendering API!
#endif
const char* version = get_version_local();
char window_title[96] = { 0 };
#ifdef GIT_HASH
snprintf(window_title, 96, "sm64ex-coop: %s [%s]", version, GIT_HASH);
#else
snprintf(window_title, 96, "sm64ex-coop: %s", version);
#endif
gfx_init(wm_api, rendering_api, window_title);
wm_api->set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
#if defined(AAPI_SDL1) || defined(AAPI_SDL2)
if (audio_api == NULL && audio_sdl.init())
audio_api = &audio_sdl;
#endif
if (audio_api == NULL) {
audio_api = &audio_null;
// incase the loading screen failed, or is disabled
if (!gGfxInited) {
gfx_init(&WAPI, &RAPI, TITLE);
WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input);
}
#if defined(AAPI_SDL1) || defined(AAPI_SDL2)
if (audio_api == NULL && audio_sdl.init()) { audio_api = &audio_sdl; }
#endif
if (audio_api == NULL) { audio_api = &audio_null; }
audio_init();
sound_init();
bassh_init();
network_player_init();
thread5_game_loop(NULL);
djui_init_late();
// init network
if (gCLIOpts.Network == NT_CLIENT) {
network_set_system(NS_SOCKET);
snprintf(gGetHostName, MAX_CONFIG_STRING, "%s", gCLIOpts.JoinIp);
@ -387,15 +323,6 @@ void main_func(void) {
network_init(NT_NONE, false);
}
audio_init();
sound_init();
bassh_init();
network_player_init();
thread5_game_loop(NULL);
inited = true;
#ifdef EXTERNAL_DATA
// precache data if needed
if (configPrecacheRes) {
@ -405,10 +332,12 @@ void main_func(void) {
}
#endif
gGameInited = true;
while (true) {
debug_context_reset();
CTX_BEGIN(CTX_FRAME);
wm_api->main_loop(produce_one_frame);
WAPI.main_loop(produce_one_frame);
#ifdef DISCORD_SDK
discord_update();
#endif

View File

@ -5,6 +5,66 @@
extern "C" {
#endif
#include "gfx/gfx_pc.h"
#include "gfx/gfx_opengl.h"
#include "gfx/gfx_direct3d11.h"
#include "gfx/gfx_direct3d12.h"
#include "gfx/gfx_dxgi.h"
#include "gfx/gfx_sdl.h"
#include "gfx/gfx_dummy.h"
#if defined(WAPI_SDL1) || defined(WAPI_SDL2)
# define WAPI gfx_sdl
#elif defined(WAPI_DXGI)
# define WAPI gfx_dxgi
#elif defined(WAPI_DUMMY)
# define WAPI gfx_dummy_wm_api
#else
# error No window API!
#endif
#if defined(RAPI_D3D11)
# define RAPI gfx_direct3d11_api
# define RAPI_NAME "DirectX 11"
#elif defined(RAPI_D3D12)
# define RAPI gfx_direct3d12_api
# define RAPI_NAME "DirectX 12"
#elif defined(RAPI_GL) || defined(RAPI_GL_LEGACY)
# define RAPI gfx_opengl_api
# ifdef USE_GLES
# define RAPI_NAME "OpenGL ES"
# else
# define RAPI_NAME "OpenGL"
# endif
#elif defined(RAPI_DUMMY)
# define RAPI gfx_dummy_renderer_api
#else
# error No rendering API!
#endif
// For IDEs with syntax highlighting
#ifndef WAPI
#define WAPI gfx_dummy_wm_api
#endif
#ifndef RAPI
#define RAPI gfx_dummy_renderer_api
#endif
#ifdef GIT_HASH
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "sm64ex-coop: %s [%s]", get_version_local(), GIT_HASH); title; })
#else
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "sm64ex-coop: %s", get_version_local()); title; })
#endif
#define LOAD_STEPS 6
#define AT_STARTUP __attribute__((constructor))
extern bool gGameInited;
extern bool gGfxInited;
extern struct GfxWindowManagerAPI* wm_api;
void game_deinit(void);
void game_exit(void);

View File

@ -168,17 +168,6 @@ void delta_interpolate_rgba(u8* res, u8* a, u8* b, f32 delta) {
res[3] = ((a[3] * antiDelta) + (b[3] * delta));
}
/*
void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
f32 antiDelta = 1.0f - delta;
for (s32 i = 0; i < 4; i++) {
for (s32 j = 0; j < 4; j++) {
out->m[i][j] = (a->m[i][j] * antiDelta) + (b->m[i][j] * delta);
}
}
}
*/
static f32 get_quat_compo_abs(f32 xPiece, f32 yPiece, f32 zPiece) {
return sqrt((1.0f + xPiece + yPiece + zPiece) * 0.25f);
}
@ -308,7 +297,7 @@ static void rot_quat_slerp(Vec4f out, Vec4f a, Vec4f b, f32 t) {
}
// removes scaling from the shear value
static f32 unmat_unscale_shear(f32 shear, f32 scale) {
inline static f32 unmat_unscale_shear(f32 shear, f32 scale) {
if (scale == 0.0f) {
// assume no shear
return 0.0f;
@ -325,14 +314,14 @@ static f32 unmat_unscale_shear(f32 shear, f32 scale) {
//
// matrix perspective is not used in SM64, so those indices are stripped from the output parameter
// return value was related to if matrix was non-singular, which was necessary for perspective
// since perspective is not used, the return value is also strippped
// since perspective is not used, the return value is also stripped
//
// additionally, rotation is not converted to euler angles
// instead, it is converted to a quaternion to avoid gimbal lock
//
// tranfs is returned as follows:
// scale(x, y, z), shear(xy, xz, zy), rotation(a, b, c, d), translation(x, y, z)
static void unmatrix(Mtx * mat, f32 tranfs[13]) {
OPTIMIZE_O3 static void unmatrix(Mtx * mat, f32 tranfs[13]) {
int i = 0;
Vec3f axisVecs[3] = { 0 };
Vec3f yzCross = { 0 };
@ -433,7 +422,7 @@ static void unmatrix(Mtx * mat, f32 tranfs[13]) {
// builds a transformation matrix from a decomposed sequence from unmatrix
// see unmatrix for what tranfs means
static void rematrix(Mtx * mat, f32 tranfs[13]) {
OPTIMIZE_O3 static void rematrix(Mtx * mat, f32 tranfs[13]) {
int i;
Vec3f rotAxes[3] = { 0 };
Mat4 rotMat = { 0 };
@ -479,7 +468,7 @@ static void rematrix(Mtx * mat, f32 tranfs[13]) {
}
}
void delta_interpolate_mtx_accurate(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
OPTIMIZE_O3 inline static void delta_interpolate_mtx_accurate(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
int i = 0;
f32 matTranfsA[13] = { 0 };
f32 matTranfsB[13] = { 0 };
@ -502,7 +491,7 @@ void delta_interpolate_mtx_accurate(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
rematrix(out, matTranfsB);
}
void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
OPTIMIZE_O3 void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta) {
// HACK: Limit accurate interpolation to 64-bit builds
if (sizeof(void*) > 4) {
if (configInterpolationMode) {