diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 1dcefd886..bd3261e6b 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -8048,6 +8048,12 @@ function network_discord_id_from_local_index(localIndex) -- ... end +--- @param levelNum integer +--- @return boolean +function level_is_vanilla_level(levelNum) + -- ... +end + --- @param scriptEntryName string --- @param courseNum integer --- @param fullName string @@ -8308,9 +8314,9 @@ function camera_unfreeze() -- ... end ---- @param levelNum integer +--- @param courseNum integer --- @return boolean -function course_is_main_course(levelNum) +function course_is_main_course(courseNum) -- ... end diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 81b5f76d5..20617c6ae 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -338,6 +338,7 @@ --- @field public echoLevel3 integer --- @field public fullName string --- @field public levelNum integer +--- @field public modIndex integer --- @field public next CustomLevelInfo --- @field public script Pointer_LevelScript --- @field public scriptEntryName string diff --git a/data/dynos.c.h b/data/dynos.c.h index fe68bbf18..daf47b175 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -62,6 +62,8 @@ u64 dynos_level_cmd_get(void *cmd, u64 offset); void dynos_level_cmd_next(void *cmd, u64 cmdsize); 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); +bool dynos_level_is_vanilla_level(s32 level); // -- behaviors -- // void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName); diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index ccbbf46f6..c5f10c8c7 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -814,9 +814,11 @@ void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory); s32 DynOS_Level_GetCount(); const s32 *DynOS_Level_GetList(); s32 DynOS_Level_GetCourse(s32 aLevel); -void DynOS_Level_Override(void* originalScript, void* newScript); +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); diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index a2136df0d..f673ea70c 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -200,6 +200,14 @@ void* dynos_level_get_script(s32 level) { return (void *) DynOS_Level_GetScript(level); } +s32 dynos_level_get_mod_index(s32 level) { + return DynOS_Level_GetModIndex(level); +} + +bool dynos_level_is_vanilla_level(s32 level) { + return DynOS_Level_IsVanillaLevel(level); +} + // -- Behaviors -- // void dynos_add_behavior(s32 modIndex, const char *filePath, const char *behaviorName) { diff --git a/data/dynos_level.cpp b/data/dynos_level.cpp index 5da78229d..0d45717f9 100644 --- a/data/dynos_level.cpp +++ b/data/dynos_level.cpp @@ -46,7 +46,14 @@ struct DynosWarp { /* 9 */ s16 mDestId = 0; }; -static void *sDynosLevelScripts[LEVEL_COUNT] = { NULL }; +struct DynosLevelScript { + void *mLevelScript; + s32 mModIndex; +}; + +#define DYNOS_LEVEL_MOD_INDEX_VANILLA (-1) + +static DynosLevelScript sDynosLevelScripts[LEVEL_COUNT] = { { NULL, DYNOS_LEVEL_MOD_INDEX_VANILLA } }; static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL }; static Array sDynosLevelWarps[LEVEL_COUNT] = { Array() }; static Array sDynosLevelList = Array(); // Ordered by Course Id, COURSE_NONE excluded @@ -90,8 +97,9 @@ static s32 DynOS_Level_PreprocessMasterScript(u8 aType, void *aCmd) { // EXECUTE if (aType == 0x00) { void *_Script = (void *) DynOS_Level_CmdGet(aCmd, 0x0C); - if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum]) { - sDynosLevelScripts[sDynosLevelNum] = _Script; + if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum].mLevelScript) { + sDynosLevelScripts[sDynosLevelNum].mLevelScript = _Script; + sDynosLevelScripts[sDynosLevelNum].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA; sDynosLevelScriptsOriginal[sDynosLevelNum] = _Script; } sDynosLevelNum = -1; @@ -190,8 +198,8 @@ static void DynOS_Level_Init() { // Level warps for (sDynosCurrentLevelNum = 0; sDynosCurrentLevelNum != LEVEL_COUNT; ++sDynosCurrentLevelNum) { - if (sDynosLevelScripts[sDynosCurrentLevelNum]) { - DynOS_Level_ParseScript(sDynosLevelScripts[sDynosCurrentLevelNum], DynOS_Level_PreprocessScript); + if (sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript) { + DynOS_Level_ParseScript(sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript, DynOS_Level_PreprocessScript); } } @@ -228,13 +236,14 @@ s32 DynOS_Level_GetCourse(s32 aLevel) { return (s32) gLevelToCourseNumTable[aLevel - 1]; } -void DynOS_Level_Override(void* originalScript, void* newScript) { +void DynOS_Level_Override(void* originalScript, void* newScript, s32 modIndex) { for (s32 i = 0; i < LEVEL_COUNT; i++) { - if (sDynosLevelScripts[i] == originalScript) { + if (sDynosLevelScripts[i].mLevelScript == originalScript) { sDynosCurrentLevelNum = i; sDynosLevelWarps[i].Clear(); DynOS_Level_ParseScript(newScript, DynOS_Level_PreprocessScript); - sDynosLevelScripts[i] = newScript; + sDynosLevelScripts[i].mLevelScript = newScript; + sDynosLevelScripts[i].mModIndex = modIndex; return; } } @@ -244,8 +253,9 @@ void DynOS_Level_Unoverride() { for (s32 i = 0; i < LEVEL_COUNT; i++) { sDynosCurrentLevelNum = i; sDynosLevelWarps[i].Clear(); - sDynosLevelScripts[i] = sDynosLevelScriptsOriginal[i]; - DynOS_Level_ParseScript(sDynosLevelScripts[i], DynOS_Level_PreprocessScript); + sDynosLevelScripts[i].mLevelScript = sDynosLevelScriptsOriginal[i]; + sDynosLevelScripts[i].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA; + DynOS_Level_ParseScript(sDynosLevelScripts[i].mLevelScript, DynOS_Level_PreprocessScript); } } @@ -257,7 +267,25 @@ const void *DynOS_Level_GetScript(s32 aLevel) { } DynOS_Level_Init(); - return sDynosLevelScripts[aLevel]; + return sDynosLevelScripts[aLevel].mLevelScript; +} + +s32 DynOS_Level_GetModIndex(s32 aLevel) { + if (aLevel >= CUSTOM_LEVEL_NUM_START) { + struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel); + if (!info || !info->script) { return DYNOS_LEVEL_MOD_INDEX_VANILLA; } + return info->modIndex; + } + + DynOS_Level_Init(); + return sDynosLevelScripts[aLevel].mModIndex; +} + +bool DynOS_Level_IsVanillaLevel(s32 aLevel) { + if (aLevel >= 0 && aLevel < LEVEL_COUNT) { + return sDynosLevelScripts[aLevel].mLevelScript == sDynosLevelScriptsOriginal[aLevel]; + } + return false; } // @@ -886,11 +914,11 @@ s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea) { extern const LevelScript level_castle_grounds_entry[]; extern const LevelScript level_castle_inside_entry[]; extern const LevelScript level_castle_courtyard_entry[]; - if (sDynosLevelScripts[aLevel] == level_castle_inside_entry) { + if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_inside_entry) { return DynOS_Level_GetWarp(aLevel, aArea, (aArea == 3) ? 0x00 : 0x01); - } else if (sDynosLevelScripts[aLevel] == level_castle_grounds_entry) { + } else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_grounds_entry) { return DynOS_Level_GetWarp(aLevel, aArea, 0x00); - } else if (sDynosLevelScripts[aLevel] == level_castle_courtyard_entry) { + } else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_courtyard_entry) { return DynOS_Level_GetWarp(aLevel, aArea, 0x01); } } diff --git a/data/dynos_mgr_lvl.cpp b/data/dynos_mgr_lvl.cpp index 05abe5c2e..8cd5c27e9 100644 --- a/data/dynos_mgr_lvl.cpp +++ b/data/dynos_mgr_lvl.cpp @@ -90,7 +90,7 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLev return; } - DynOS_Level_Override((void*)originalScript, newScriptNode->mData); + DynOS_Level_Override((void*)originalScript, newScriptNode->mData, modIndex); _OverrideLevelScripts.Add({ originalScript, newScriptNode->mData, _Node}); } diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index c72d6c192..89c0b44fb 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -7285,6 +7285,26 @@
+## [level_is_vanilla_level](#level_is_vanilla_level) + +### Lua Example +`local booleanValue = level_is_vanilla_level(levelNum)` + +### Parameters +| Field | Type | +| ----- | ---- | +| levelNum | `integer` | + +### Returns +- `boolean` + +### C Prototype +`bool level_is_vanilla_level(s16 levelNum);` + +[:arrow_up_small:](#) + +
+ ## [level_register](#level_register) ### Lua Example @@ -8133,18 +8153,18 @@ ## [course_is_main_course](#course_is_main_course) ### Lua Example -`local booleanValue = course_is_main_course(levelNum)` +`local booleanValue = course_is_main_course(courseNum)` ### Parameters | Field | Type | | ----- | ---- | -| levelNum | `integer` | +| courseNum | `integer` | ### Returns - `boolean` ### C Prototype -`bool course_is_main_course(u16 levelNum);` +`bool course_is_main_course(u16 courseNum);` [:arrow_up_small:](#) diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 61f57a468..fbfaef7a6 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1498,6 +1498,7 @@
- smlua_level_utils.h + - [level_is_vanilla_level](functions-4.md#level_is_vanilla_level) - [level_register](functions-4.md#level_register) - [smlua_level_util_get_info](functions-4.md#smlua_level_util_get_info) - [smlua_level_util_get_info_from_short_name](functions-4.md#smlua_level_util_get_info_from_short_name) diff --git a/docs/lua/structs.md b/docs/lua/structs.md index b7295a573..56b3858c6 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -538,6 +538,7 @@ | echoLevel3 | `integer` | | | fullName | `string` | read-only | | levelNum | `integer` | | +| modIndex | `integer` | | | next | [CustomLevelInfo](structs.md#CustomLevelInfo) | | | script | `Pointer` <`LevelScript`> | read-only | | scriptEntryName | `string` | read-only | diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index b875b0736..96793386e 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -394,7 +394,7 @@ static struct LuaObjectField sControllerFields[LUA_CONTROLLER_FIELD_COUNT] = { { "stickY", LVT_F32, offsetof(struct Controller, stickY), false, LOT_NONE }, }; -#define LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT 11 +#define LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT 12 static struct LuaObjectField sCustomLevelInfoFields[LUA_CUSTOM_LEVEL_INFO_FIELD_COUNT] = { { "acousticReach", LVT_U32, offsetof(struct CustomLevelInfo, acousticReach), false, LOT_NONE }, { "courseNum", LVT_S16, offsetof(struct CustomLevelInfo, courseNum), false, LOT_NONE }, @@ -403,6 +403,7 @@ static struct LuaObjectField sCustomLevelInfoFields[LUA_CUSTOM_LEVEL_INFO_FIELD_ { "echoLevel3", LVT_U32, offsetof(struct CustomLevelInfo, echoLevel3), false, LOT_NONE }, { "fullName", LVT_STRING_P, offsetof(struct CustomLevelInfo, fullName), true, LOT_NONE }, { "levelNum", LVT_S16, offsetof(struct CustomLevelInfo, levelNum), false, LOT_NONE }, + { "modIndex", LVT_S32, offsetof(struct CustomLevelInfo, modIndex), false, LOT_NONE }, { "next", LVT_COBJECT_P, offsetof(struct CustomLevelInfo, next), false, LOT_CUSTOMLEVELINFO }, { "script", LVT_LEVELSCRIPT_P, offsetof(struct CustomLevelInfo, script), true, LOT_POINTER }, { "scriptEntryName", LVT_STRING_P, offsetof(struct CustomLevelInfo, scriptEntryName), true, LOT_NONE }, diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index 4d9f30a54..2cc491c4c 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -9,6 +9,7 @@ #include "audio/external.h" #include "object_fields.h" #include "engine/math_util.h" +#include "engine/level_script.h" #include "pc/djui/djui_hud_utils.h" #include "include/level_misc_macros.h" #include "include/macro_presets.h" @@ -499,23 +500,41 @@ s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) { // OBJECT_WITH_ACTS_EXT case 0x3F: { - const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 20)); - if (bhvStr) { - bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); - bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); - pBhvId = &bhvId; - pBhvArgs = &bhvArgs; + if (gLevelScriptModIndex != -1) { + const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 20)); + if (bhvStr) { + gSmLuaConvertSuccess = true; + bhvId = (u32) smlua_get_integer_mod_variable(gLevelScriptModIndex, bhvStr); + if (!gSmLuaConvertSuccess) { + gSmLuaConvertSuccess = true; + bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); + } + if (gSmLuaConvertSuccess) { + bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); + pBhvId = &bhvId; + pBhvArgs = &bhvArgs; + } + } } } break; // OBJECT_WITH_ACTS_EXT2 case 0x40: { - const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 24)); - if (bhvStr) { - bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); - bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); - pBhvId = &bhvId; - pBhvArgs = &bhvArgs; + if (gLevelScriptModIndex != -1) { + const char *bhvStr = dynos_level_get_token(dynos_level_cmd_get(cmd, 24)); + if (bhvStr) { + gSmLuaConvertSuccess = true; + bhvId = (u32) smlua_get_integer_mod_variable(gLevelScriptModIndex, bhvStr); + if (!gSmLuaConvertSuccess) { + gSmLuaConvertSuccess = true; + bhvId = (u32) smlua_get_any_integer_mod_variable(bhvStr); + } + if (gSmLuaConvertSuccess) { + bhvArgs = (u32) dynos_level_cmd_get(cmd, 16); + pBhvId = &bhvId; + pBhvArgs = &bhvArgs; + } + } } } break; @@ -612,7 +631,20 @@ void smlua_func_level_script_parse(lua_State* L) { LOG_LUA("Failed to find script: %lld", levelNum); return; } + s32 modIndex = dynos_level_get_mod_index(levelNum); + + // Back up current values + LevelScript *currLevelScript = gLevelScriptActive; + s32 currModIndex = gLevelScriptModIndex; + + // Parse script + gLevelScriptActive = (LevelScript *) script; + gLevelScriptModIndex = modIndex; dynos_level_parse_script(script, smlua_func_level_script_parse_callback); + + // Restore current values + gLevelScriptActive = currLevelScript; + gLevelScriptModIndex = currModIndex; } ////////// diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index a77695cc5..af1517a18 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -26369,6 +26369,23 @@ int smlua_func_network_discord_id_from_local_index(lua_State* L) { // smlua_level_utils.h // ///////////////////////// +int smlua_func_level_is_vanilla_level(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", "level_is_vanilla_level", 1, top); + return 0; + } + + s16 levelNum = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "level_is_vanilla_level"); return 0; } + + lua_pushboolean(L, level_is_vanilla_level(levelNum)); + + return 1; +} + int smlua_func_level_register(lua_State* L) { if (L == NULL) { return 0; } @@ -27116,10 +27133,10 @@ int smlua_func_course_is_main_course(lua_State* L) { return 0; } - u16 levelNum = smlua_to_integer(L, 1); + u16 courseNum = smlua_to_integer(L, 1); if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "course_is_main_course"); return 0; } - lua_pushboolean(L, course_is_main_course(levelNum)); + lua_pushboolean(L, course_is_main_course(courseNum)); return 1; } @@ -30722,6 +30739,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "network_discord_id_from_local_index", smlua_func_network_discord_id_from_local_index); // smlua_level_utils.h + smlua_bind_function(L, "level_is_vanilla_level", smlua_func_level_is_vanilla_level); smlua_bind_function(L, "level_register", smlua_func_level_register); 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_short_name", smlua_func_smlua_level_util_get_info_from_short_name); diff --git a/src/pc/lua/utils/smlua_level_utils.c b/src/pc/lua/utils/smlua_level_utils.c index 7500d5b40..11988e342 100644 --- a/src/pc/lua/utils/smlua_level_utils.c +++ b/src/pc/lua/utils/smlua_level_utils.c @@ -106,6 +106,27 @@ s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullN info->echoLevel1 = echoLevel1; info->echoLevel2 = echoLevel2; info->echoLevel3 = echoLevel3; + if (gLuaLoadingMod) { + info->modIndex = gLuaLoadingMod->index; + } else if (gLuaActiveMod) { + info->modIndex = gLuaActiveMod->index; + } else { + if (info->scriptEntryName) { + free(info->scriptEntryName); + info->scriptEntryName = NULL; + } + if (info->fullName) { + free(info->fullName); + info->fullName = NULL; + } + if (info->shortName) { + free(info->shortName); + info->shortName = NULL; + } + free(info); + LOG_LUA("Failed to find mod index for level: %s", scriptEntryName); + return 0; + } // add to list if (!sCustomLevelHead) { @@ -126,6 +147,10 @@ s16 level_register(const char* scriptEntryName, s16 courseNum, const char* fullN return 0; } +bool level_is_vanilla_level(s16 levelNum) { + return dynos_level_is_vanilla_level(levelNum); +} + bool warp_to_warpnode(s32 aLevel, s32 aArea, s32 aAct, s32 aWarpId) { return dynos_warp_to_warpnode(aLevel, aArea, aAct, aWarpId); } diff --git a/src/pc/lua/utils/smlua_level_utils.h b/src/pc/lua/utils/smlua_level_utils.h index 107c80601..31ce7f6ad 100644 --- a/src/pc/lua/utils/smlua_level_utils.h +++ b/src/pc/lua/utils/smlua_level_utils.h @@ -12,6 +12,7 @@ struct CustomLevelInfo { u32 echoLevel1; u32 echoLevel2; u32 echoLevel3; + s32 modIndex; struct CustomLevelInfo* next; }; @@ -21,6 +22,7 @@ void smlua_level_util_reset(void); struct CustomLevelInfo* smlua_level_util_get_info(s16 levelNum); struct CustomLevelInfo* smlua_level_util_get_info_from_short_name(char* shortName); 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); bool warp_to_level(s32 aLevel, s32 aArea, s32 aAct); bool warp_restart_level(void); diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index 228bec23a..5cfb7f6e4 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -448,8 +448,8 @@ void set_override_skybox(s8 background) { /// -bool course_is_main_course(u16 levelNum) { - return COURSE_IS_MAIN_COURSE(levelNum); +bool course_is_main_course(u16 courseNum) { + return COURSE_IS_MAIN_COURSE(courseNum); } /// diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h index b3c336ce3..88410f307 100644 --- a/src/pc/lua/utils/smlua_misc_utils.h +++ b/src/pc/lua/utils/smlua_misc_utils.h @@ -101,7 +101,7 @@ void set_override_skybox(s8 background); void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue); -bool course_is_main_course(u16 levelNum); +bool course_is_main_course(u16 courseNum); s16 get_ttc_speed_setting(); void set_ttc_speed_setting(s16 speed);