diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index 7f1480a8..357081cc 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -214,3 +214,10 @@ end function djui_hud_render_texture_tile_interpolated(texInfo, prevX, prevY, prevScaleW, prevScaleH, x, y, scaleW, scaleH, tileX, tileY, tileW, tileH) -- ... end + +--- @param levelNum number +--- @param func fun(areaNum:number, bhv:table) +--- @return nil +function level_script_parse(levelNum, func) + -- ... +end diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 7d5100b0..eb579551 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -629,6 +629,7 @@ --- @class LevelValues --- @field public cellHeightLimit integer --- @field public coinsRequiredForCoinStar integer +--- @field public disableActs boolean --- @field public entryLevel LevelNum --- @field public exitCastleArea integer --- @field public exitCastleLevel LevelNum diff --git a/data/dynos.c.h b/data/dynos.c.h index 47f811ad..3d047e4f 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -57,6 +57,10 @@ void dynos_add_level(s32 modIndex, const char *filePath, const char* levelName); 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_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *)); +void* dynos_level_get_script(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 0b55f360..97072fdc 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -822,6 +822,9 @@ 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); +void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)); // // Warps diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index bfdb2ff5..f054cb3e 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -179,6 +179,22 @@ void dynos_level_load_background(void *ptr) { DynOS_Lvl_LoadBackground(ptr); } +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_parse_script(const void *script, s32 (*aPreprocessFunction)(u8, void *)) { + DynOS_Level_ParseScript(script, aPreprocessFunction); +} + +void* dynos_level_get_script(s32 level) { + return (void *) DynOS_Level_GetScript(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 7998d3f7..5da78229 100644 --- a/data/dynos_level.cpp +++ b/data/dynos_level.cpp @@ -51,17 +51,17 @@ static void *sDynosLevelScriptsOriginal[LEVEL_COUNT] = { NULL }; static Array sDynosLevelWarps[LEVEL_COUNT] = { Array() }; static Array sDynosLevelList = Array(); // Ordered by Course Id, COURSE_NONE excluded -static u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) { +u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) { u64 _Offset = (((aOffset) & 3llu) | (((aOffset) & ~3llu) << (sizeof(void *) >> 3llu))); return *((u64 *) (u64(aCmd) + _Offset)); } -static void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) { +void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) { u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu))); return (void *) (u64(aCmd) + _Offset); } -static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)); +void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)); // // Init @@ -752,7 +752,7 @@ static LvlCmd *DynOS_Level_CmdJumpArea(Stack &aStack, LvlCmd *aCmd, s32 (*aPrepr return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize); } -static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) { +void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) { Stack _Stack; _Stack.mBaseIndex = -1; _Stack.mTopIndex = 0; diff --git a/docs/lua/structs.md b/docs/lua/structs.md index a90a0ae9..9a7eed4d 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -924,6 +924,7 @@ | ----- | ---- | ------ | | cellHeightLimit | `integer` | | | coinsRequiredForCoinStar | `integer` | | +| disableActs | `boolean` | | | entryLevel | [enum LevelNum](constants.md#enum-LevelNum) | | | exitCastleArea | `integer` | | | exitCastleLevel | [enum LevelNum](constants.md#enum-LevelNum) | | diff --git a/src/engine/level_script.c b/src/engine/level_script.c index 26680dae..7f0b764b 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -28,6 +28,7 @@ #include "src/pc/lua/utils/smlua_model_utils.h" #include "src/pc/lua/smlua.h" #include "src/pc/djui/djui.h" +#include "game/hardcoded.h" #define CMD_GET(type, offset) (*(type *) (CMD_PROCESS_OFFSET(offset) + (u8 *) sCurrentCmd)) @@ -506,7 +507,7 @@ static void level_cmd_place_object(void) { u16 model; struct SpawnInfo *spawnInfo; - if (sCurrAreaIndex != -1 && ((CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) { + if (sCurrAreaIndex != -1 && (gLevelValues.disableActs || (CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) { model = CMD_GET(u8, 3); spawnInfo = alloc_only_pool_alloc(sLevelPool, sizeof(struct SpawnInfo)); diff --git a/src/game/hardcoded.c b/src/game/hardcoded.c index c5d11cf1..c2746086 100644 --- a/src/game/hardcoded.c +++ b/src/game/hardcoded.c @@ -97,6 +97,7 @@ struct LevelValues gDefaultLevelValues = { .floorLowerLimit = FLOOR_LOWER_LIMIT, .floorLowerLimitMisc = FLOOR_LOWER_LIMIT_MISC, .floorLowerLimitShadow = FLOOR_LOWER_LIMIT_SHADOW, + .disableActs = false, }; struct LevelValues gLevelValues = { 0 }; diff --git a/src/game/hardcoded.h b/src/game/hardcoded.h index 2f9b8b06..f3354b52 100644 --- a/src/game/hardcoded.h +++ b/src/game/hardcoded.h @@ -62,6 +62,7 @@ struct LevelValues { s16 floorLowerLimit; s16 floorLowerLimitMisc; s16 floorLowerLimitShadow; + bool disableActs; }; extern struct LevelValues gLevelValues; diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 5772fdda..47651649 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -726,10 +726,11 @@ static struct LuaObjectField sLakituStateFields[LUA_LAKITU_STATE_FIELD_COUNT] = { "yaw", LVT_S16, offsetof(struct LakituState, yaw), false, LOT_NONE }, }; -#define LUA_LEVEL_VALUES_FIELD_COUNT 24 +#define LUA_LEVEL_VALUES_FIELD_COUNT 25 static struct LuaObjectField sLevelValuesFields[LUA_LEVEL_VALUES_FIELD_COUNT] = { { "cellHeightLimit", LVT_S16, offsetof(struct LevelValues, cellHeightLimit), false, LOT_NONE }, { "coinsRequiredForCoinStar", LVT_S16, offsetof(struct LevelValues, coinsRequiredForCoinStar), false, LOT_NONE }, + { "disableActs", LVT_BOOL, offsetof(struct LevelValues, disableActs), false, LOT_NONE }, { "entryLevel", LVT_S32, offsetof(struct LevelValues, entryLevel), false, LOT_NONE }, { "exitCastleArea", LVT_S16, offsetof(struct LevelValues, exitCastleArea), false, LOT_NONE }, { "exitCastleLevel", LVT_S32, offsetof(struct LevelValues, exitCastleLevel), false, LOT_NONE }, diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index 23c60b37..9f595df5 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -10,6 +10,8 @@ #include "object_fields.h" #include "engine/math_util.h" #include "pc/djui/djui_hud_utils.h" +#include "include/level_misc_macros.h" +#include "include/macro_presets.h" bool smlua_functions_valid_param_count(lua_State* L, int expected) { int top = lua_gettop(L); @@ -459,6 +461,122 @@ int smlua_func_djui_hud_render_texture_tile_interpolated(lua_State* L) { return 1; } + //////////////////////////////// + // level script preprocessing // +//////////////////////////////// + +struct LuaLevelScriptParse { + int reference; + struct Mod* mod; +}; + +struct LuaLevelScriptParse sLevelScriptParse = { 0 }; + +s32 smlua_func_level_script_parse_callback(u8 type, void *cmd) { + if (type != 0x24 && type != 0x39 && type != 0x1F) { + return 0; + } + lua_State* L = gLuaState; + if (L == NULL) { return 0; } + struct LuaLevelScriptParse* preprocess = &sLevelScriptParse; + + lua_rawgeti(L, LUA_REGISTRYINDEX, preprocess->reference); + + if (type == 0x1F) { + u8 area = (u8) dynos_level_cmd_get(cmd, 2); + lua_pushinteger(L, area); + } else { + lua_pushnil(L); + } + + if (type == 0x24) { + const BehaviorScript *bhv = (const BehaviorScript *) dynos_level_cmd_get(cmd, 20); + u32 behaviorArg = (u32) dynos_level_cmd_get(cmd, 16); + + lua_newtable(L); + + lua_pushstring(L, "behavior"); + lua_pushinteger(L, get_id_from_behavior(bhv)); + lua_settable(L, -3); + + lua_pushstring(L, "behaviorArg"); + lua_pushinteger(L, behaviorArg); + lua_settable(L, -3); + } else { + lua_pushnil(L); + } + + if (type == 0x39) { + MacroObject *data = (MacroObject *) dynos_level_cmd_get(cmd, 4); + int i = 0; + s32 len = 0; + + lua_newtable(L); + int t = lua_gettop(gLuaState); + + lua_newtable(L); + int args = lua_gettop(gLuaState); + while (data[len++] != MACRO_OBJECT_END()) { + s32 presetId = (s32) ((data[len - 1] & 0x1FF) - 0x1F); + const BehaviorScript *bhv = (const BehaviorScript *) MacroObjectPresets[presetId].behavior; + s32 presetParams = MacroObjectPresets[presetId].param; + s32 objParams = (data[4] & 0xFF00) + (presetParams & 0x00FF); + u32 behaviorArg = ((objParams & 0x00FF) << 16) + (objParams & 0xFF00); + + lua_pushinteger(L, i); + lua_pushinteger(L, get_id_from_behavior(bhv)); + lua_settable(L, t); + + lua_pushinteger(L, i); + lua_pushinteger(L, behaviorArg); + lua_settable(L, args); + + i++; + len += 4; + } + } else { + lua_pushnil(L); + lua_pushnil(L); + } + + // call the callback + if (0 != smlua_call_hook(L, 4, 0, 0, preprocess->mod)) { + LOG_LUA("Failed to call the callback behaviors: %u", type); + return 0; + } +} + +void smlua_func_level_script_parse(lua_State* L) { + if (!smlua_functions_valid_param_count(L, 2)) { return; } + + lua_Integer levelNum = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { + LOG_LUA_LINE("Invalid level script name"); + return; + } + + struct LuaLevelScriptParse* preprocess = &sLevelScriptParse; + preprocess->reference = LUA_NOREF; + + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if (ref == -1) { + LOG_LUA_LINE("Level Script Parse: %lld tried to parse using undefined function", levelNum); + return; + } + + preprocess->reference = ref; + preprocess->mod = gLuaActiveMod; + + void *script = dynos_level_get_script(levelNum); + if (script == NULL) { + LOG_LUA("Failed to find script: %lld", levelNum); + return; + } + dynos_level_parse_script(script, smlua_func_level_script_parse_callback); +} + ////////// // bind // ////////// @@ -482,4 +600,5 @@ void smlua_bind_functions(void) { smlua_bind_function(L, "djui_hud_render_texture_tile", smlua_func_djui_hud_render_texture_tile); smlua_bind_function(L, "djui_hud_render_texture_interpolated", smlua_func_djui_hud_render_texture_interpolated); smlua_bind_function(L, "djui_hud_render_texture_tile_interpolated", smlua_func_djui_hud_render_texture_tile_interpolated); + smlua_bind_function(L, "level_script_parse", smlua_func_level_script_parse); }