From 17d12bc5ca39ec8063e5a75d281964cfab861a48 Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Mar 2026 15:01:49 -0500 Subject: [PATCH 1/3] Add playmode hooks --- autogen/lua_definitions/constants.lua | 6 ++- docs/lua/constants.md | 4 +- src/game/level_update.c | 59 +++++++++++++++--------- src/pc/lua/smlua_constants_autogen.c | 4 +- src/pc/lua/smlua_hook_events.inl | 2 + src/pc/lua/smlua_hook_events_autogen.inl | 59 ++++++++++++++++++++++++ src/pc/lua/smlua_hooks.h | 2 + 7 files changed, 110 insertions(+), 26 deletions(-) diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 1d7dfb2dc..d94a0a9a7 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -8213,7 +8213,9 @@ HOOK_ON_FIND_FLOOR = 62 --- @type LuaHookedEventType HOOK_ON_FIND_WATER_LEVEL = 63 --- @type LuaHookedEventType HOOK_ON_FIND_POISON_GAS_LEVEL = 64 --- @type LuaHookedEventType HOOK_ON_FIND_SURFACE_ON_RAY = 65 --- @type LuaHookedEventType -HOOK_MAX = 66 --- @type LuaHookedEventType +HOOK_BEFORE_PLAY_MODE_RUN = 66 --- @type LuaHookedEventType +HOOK_ON_PLAY_MODE_RUN = 67 --- @type LuaHookedEventType +HOOK_MAX = 68 --- @type LuaHookedEventType --- @alias LuaHookedEventType --- | `HOOK_UPDATE` @@ -8282,6 +8284,8 @@ HOOK_MAX = 66 --- @type LuaHookedEventType --- | `HOOK_ON_FIND_WATER_LEVEL` --- | `HOOK_ON_FIND_POISON_GAS_LEVEL` --- | `HOOK_ON_FIND_SURFACE_ON_RAY` +--- | `HOOK_BEFORE_PLAY_MODE_RUN` +--- | `HOOK_ON_PLAY_MODE_RUN` --- | `HOOK_MAX` --- @type integer diff --git a/docs/lua/constants.md b/docs/lua/constants.md index cf00279f7..797688868 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -3543,7 +3543,9 @@ | HOOK_ON_FIND_WATER_LEVEL | 63 | | HOOK_ON_FIND_POISON_GAS_LEVEL | 64 | | HOOK_ON_FIND_SURFACE_ON_RAY | 65 | -| HOOK_MAX | 66 | +| HOOK_BEFORE_PLAY_MODE_RUN | 66 | +| HOOK_ON_PLAY_MODE_RUN | 67 | +| HOOK_MAX | 68 | - MAX_HOOKED_BEHAVIORS [:arrow_up_small:](#) diff --git a/src/game/level_update.c b/src/game/level_update.c index 1ad390601..91a0d4a48 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1504,6 +1504,41 @@ UNUSED static s32 play_mode_unused(void) { return 0; } +s32 run_current_play_mode() { + s32 changeLevel = 0; + + s16 hookPlaymode = sCurrPlayMode; + if (smlua_call_event_hooks(HOOK_BEFORE_PLAY_MODE_RUN, sCurrPlayMode, &hookPlaymode)) { + sCurrPlayMode = hookPlaymode; + } + + switch (sCurrPlayMode) { + case PLAY_MODE_NORMAL: + changeLevel = play_mode_normal(); + break; + case PLAY_MODE_PAUSED: + if (!network_check_singleplayer_pause()) { + changeLevel = play_mode_normal(); + } + + if (sCurrPlayMode == PLAY_MODE_PAUSED) { + changeLevel = play_mode_paused(); + } + break; + case PLAY_MODE_CHANGE_AREA: + changeLevel = play_mode_change_area(); + break; + case PLAY_MODE_CHANGE_LEVEL: + changeLevel = play_mode_change_level(); + break; + case PLAY_MODE_FRAME_ADVANCE: + changeLevel = play_mode_frame_advance(); + break; + } + smlua_call_event_hooks(HOOK_ON_PLAY_MODE_RUN, sCurrPlayMode); + return changeLevel; +} + void update_menu_level(void) { // figure out level s32 curLevel = 0; @@ -1731,29 +1766,7 @@ s32 update_level(void) { gCurrentArea->localAreaTimer++; } - switch (sCurrPlayMode) { - case PLAY_MODE_NORMAL: - changeLevel = play_mode_normal(); - break; - case PLAY_MODE_PAUSED: - if (!network_check_singleplayer_pause()) { - changeLevel = play_mode_normal(); - } - - if (sCurrPlayMode == PLAY_MODE_PAUSED) { - changeLevel = play_mode_paused(); - } - break; - case PLAY_MODE_CHANGE_AREA: - changeLevel = play_mode_change_area(); - break; - case PLAY_MODE_CHANGE_LEVEL: - changeLevel = play_mode_change_level(); - break; - case PLAY_MODE_FRAME_ADVANCE: - changeLevel = play_mode_frame_advance(); - break; - } + changeLevel = run_current_play_mode(); if (changeLevel) { reset_volume(); diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index de7da771c..5813341f1 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -3553,7 +3553,9 @@ char gSmluaConstants[] = "" "HOOK_ON_FIND_WATER_LEVEL=63\n" "HOOK_ON_FIND_POISON_GAS_LEVEL=64\n" "HOOK_ON_FIND_SURFACE_ON_RAY=65\n" -"HOOK_MAX=66\n" +"HOOK_BEFORE_PLAY_MODE_RUN=66\n" +"HOOK_ON_PLAY_MODE_RUN=67\n" +"HOOK_MAX=68\n" "MAX_HOOKED_BEHAVIORS=1024\n" "HUD_DISPLAY_LIVES=0\n" "HUD_DISPLAY_COINS=1\n" diff --git a/src/pc/lua/smlua_hook_events.inl b/src/pc/lua/smlua_hook_events.inl index 71f4a915c..ced5b2434 100644 --- a/src/pc/lua/smlua_hook_events.inl +++ b/src/pc/lua/smlua_hook_events.inl @@ -64,3 +64,5 @@ SMLUA_EVENT_HOOK(HOOK_ON_FIND_FLOOR, _, f32 posX, f32 posY, f32 posZ, struct Sur SMLUA_EVENT_HOOK(HOOK_ON_FIND_WATER_LEVEL, _, f32 x, f32 z, f32 *waterLevel) // Manually defined hook SMLUA_EVENT_HOOK(HOOK_ON_FIND_POISON_GAS_LEVEL, _, f32 x, f32 z, f32 *gasLevel) // Manually defined hook SMLUA_EVENT_HOOK(HOOK_ON_FIND_SURFACE_ON_RAY, _, Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos) // Manually defined hook +SMLUA_EVENT_HOOK(HOOK_BEFORE_PLAY_MODE_RUN, HOOK_RETURN_NEVER, s16 playmode, OUTPUT s16 *overridePlaymode) +SMLUA_EVENT_HOOK(HOOK_ON_PLAY_MODE_RUN, HOOK_RETURN_NEVER, s16 playmode) \ No newline at end of file diff --git a/src/pc/lua/smlua_hook_events_autogen.inl b/src/pc/lua/smlua_hook_events_autogen.inl index 8468eb4b8..ffcb8a164 100644 --- a/src/pc/lua/smlua_hook_events_autogen.inl +++ b/src/pc/lua/smlua_hook_events_autogen.inl @@ -1863,3 +1863,62 @@ bool smlua_call_event_hooks_HOOK_ON_PACKET_BYTESTRING_RECEIVE(s32 modIndex, s32 } return hookResult; } + +bool smlua_call_event_hooks_HOOK_BEFORE_PLAY_MODE_RUN(s16 playmode, s16 *overridePlaymode) { + lua_State *L = gLuaState; + if (L == NULL) { return false; } + bool hookResult = false; + + struct LuaHookedEvent *hook = &sHookedEvents[HOOK_BEFORE_PLAY_MODE_RUN]; + for (int i = 0; i < hook->count; i++) { + s32 prevTop = lua_gettop(L); + + // push the callback onto the stack + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); + + // push playmode + lua_pushinteger(L, playmode); + + // call the callback + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { + LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_BEFORE_PLAY_MODE_RUN], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); + continue; + } + hookResult = true; + + // return overridePlaymode + if (lua_type(L, -1) == LUA_TNUMBER) { + *overridePlaymode = smlua_to_integer(L, -1); + } + + lua_settop(L, prevTop); + } + return hookResult; +} + +bool smlua_call_event_hooks_HOOK_ON_PLAY_MODE_RUN(s16 playmode) { + lua_State *L = gLuaState; + if (L == NULL) { return false; } + bool hookResult = false; + + struct LuaHookedEvent *hook = &sHookedEvents[HOOK_ON_PLAY_MODE_RUN]; + for (int i = 0; i < hook->count; i++) { + s32 prevTop = lua_gettop(L); + + // push the callback onto the stack + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); + + // push playmode + lua_pushinteger(L, playmode); + + // call the callback + if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { + LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_ON_PLAY_MODE_RUN], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); + continue; + } + hookResult = true; + + lua_settop(L, prevTop); + } + return hookResult; +} diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index c814c73e9..31102179d 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -82,6 +82,8 @@ enum LuaHookedEventType { HOOK_ON_FIND_WATER_LEVEL, HOOK_ON_FIND_POISON_GAS_LEVEL, HOOK_ON_FIND_SURFACE_ON_RAY, + HOOK_BEFORE_PLAY_MODE_RUN, + HOOK_ON_PLAY_MODE_RUN, HOOK_MAX, }; From 5b5d0b847b7ed02c5d6ae7eac532bc967e0e80fd Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:28:25 -0500 Subject: [PATCH 2/3] Add hook to docs, fix some crashes semi-related --- autogen/lua_definitions/constants.lua | 8 ++++---- docs/lua/constants.md | 4 ++-- docs/lua/guides/hooks.md | 4 +++- src/game/behaviors/bbh_tilting_trap.inc.c | 1 + .../behaviors/controllable_platform.inc.c | 1 + src/game/behaviors/dorrie.inc.c | 1 + src/game/behaviors/floating_platform.inc.c | 1 + src/game/behaviors/platform_on_track.inc.c | 1 + src/game/behaviors/seesaw_platform.inc.c | 1 + .../behaviors/tilting_inverted_pyramid.inc.c | 3 ++- src/game/level_update.c | 7 +++++-- src/pc/lua/smlua_constants_autogen.c | 4 ++-- src/pc/lua/smlua_hook_events.inl | 4 ++-- src/pc/lua/smlua_hook_events_autogen.inl | 19 ++++++++++++------- src/pc/lua/smlua_hooks.h | 4 ++-- 15 files changed, 40 insertions(+), 23 deletions(-) diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index d94a0a9a7..100d7b333 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -8213,8 +8213,8 @@ HOOK_ON_FIND_FLOOR = 62 --- @type LuaHookedEventType HOOK_ON_FIND_WATER_LEVEL = 63 --- @type LuaHookedEventType HOOK_ON_FIND_POISON_GAS_LEVEL = 64 --- @type LuaHookedEventType HOOK_ON_FIND_SURFACE_ON_RAY = 65 --- @type LuaHookedEventType -HOOK_BEFORE_PLAY_MODE_RUN = 66 --- @type LuaHookedEventType -HOOK_ON_PLAY_MODE_RUN = 67 --- @type LuaHookedEventType +HOOK_BEFORE_PLAY_MODE_UPDATE = 66 --- @type LuaHookedEventType +HOOK_ON_PLAY_MODE_UPDATE = 67 --- @type LuaHookedEventType HOOK_MAX = 68 --- @type LuaHookedEventType --- @alias LuaHookedEventType @@ -8284,8 +8284,8 @@ HOOK_MAX = 68 --- @type LuaHookedEventType --- | `HOOK_ON_FIND_WATER_LEVEL` --- | `HOOK_ON_FIND_POISON_GAS_LEVEL` --- | `HOOK_ON_FIND_SURFACE_ON_RAY` ---- | `HOOK_BEFORE_PLAY_MODE_RUN` ---- | `HOOK_ON_PLAY_MODE_RUN` +--- | `HOOK_BEFORE_PLAY_MODE_UPDATE` +--- | `HOOK_ON_PLAY_MODE_UPDATE` --- | `HOOK_MAX` --- @type integer diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 797688868..a3ec7947f 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -3543,8 +3543,8 @@ | HOOK_ON_FIND_WATER_LEVEL | 63 | | HOOK_ON_FIND_POISON_GAS_LEVEL | 64 | | HOOK_ON_FIND_SURFACE_ON_RAY | 65 | -| HOOK_BEFORE_PLAY_MODE_RUN | 66 | -| HOOK_ON_PLAY_MODE_RUN | 67 | +| HOOK_BEFORE_PLAY_MODE_UPDATE | 66 | +| HOOK_ON_PLAY_MODE_UPDATE | 67 | | HOOK_MAX | 68 | - MAX_HOOKED_BEHAVIORS diff --git a/docs/lua/guides/hooks.md b/docs/lua/guides/hooks.md index 07d522650..a5d03723b 100644 --- a/docs/lua/guides/hooks.md +++ b/docs/lua/guides/hooks.md @@ -143,7 +143,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh | HOOK_ON_GEO_PROCESS | Called when a GeoLayout is processed **Note:** You must set the `hookProcess` field of the graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex | | HOOK_BEFORE_GEO_PROCESS | Called before a GeoLayout is processed **Note:** You must set the `hookProcess` field of the graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex | | HOOK_ON_GEO_PROCESS_CHILDREN | Called when the children of a GeoLayout node is processed **Note:** You must set the `hookProcess` field of the parent graph node to a non-zero value | [GraphNode](../structs.md#GraphNode) graphNode, `integer` matStackIndex | -| HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS | Called before running Mario's geometry input logic, return `false` to not run it. | [MarioState](../structs.md) m | +| HOOK_MARIO_OVERRIDE_GEOMETRY_INPUTS | Called before running Mario's geometry input logic, return `false` to not run it. | [MarioState](../structs.md) m | | HOOK_ON_INTERACTIONS | Called when the Mario interactions are processed | [MarioState](../structs.md#MarioState) mario | | HOOK_ALLOW_FORCE_WATER_ACTION | Called when executing a non-water action while under the water's surface, or vice versa. Return `false` to prevent the player from being forced out of the action at the water's surface | [MarioState](../structs.md#MarioState) mario, `boolean` isInWaterAction | | HOOK_BEFORE_WARP | Called before the local player warps. Return a table with `destLevel`, `destArea`, `destWarpNode`, to override the warp | `integer` destLevel, `integer` destArea, `integer` destWarpNode, `integer` arg | @@ -157,6 +157,8 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh | HOOK_ON_FIND_WATER_LEVEL | Called after water level detection completes. Return a number to override the water level | `number` x, `number` z, `number` waterLevel | | HOOK_ON_FIND_POISON_GAS_LEVEL | Called after poison gas level detection completes. Return a number to override the gas level | `number` x, `number` z, `number` gasLevel | | HOOK_ON_FIND_SURFACE_ON_RAY | Called after ray-surface intersection completes. Return `surface` to override the hit surface, or `surface, hitPos` to override both | `Vec3f` orig, `Vec3f` dir, [Surface](../structs.md#Surface) hitSurface, `Vec3f` hitPos | +| HOOK_BEFORE_PLAY_MODE_UPDATE | Called before the play mode is ran. Return a number to override the play mode to be ran. | `number` playMode | +| HOOK_ON_PLAY_MODE_UPDATE | Called after the play mode is ran. Return a number to override the change level. | `number` playMode | ### Parameters diff --git a/src/game/behaviors/bbh_tilting_trap.inc.c b/src/game/behaviors/bbh_tilting_trap.inc.c index 3a810522b..3643854e6 100644 --- a/src/game/behaviors/bbh_tilting_trap.inc.c +++ b/src/game/behaviors/bbh_tilting_trap.inc.c @@ -22,6 +22,7 @@ void bhv_bbh_tilting_trap_platform_loop(void) { u8 playersTouched = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform == o) { x += gMarioStates[i].marioObj->oPosX; y += gMarioStates[i].marioObj->oPosY; diff --git a/src/game/behaviors/controllable_platform.inc.c b/src/game/behaviors/controllable_platform.inc.c index e1b8583ff..b93bbb6f0 100644 --- a/src/game/behaviors/controllable_platform.inc.c +++ b/src/game/behaviors/controllable_platform.inc.c @@ -183,6 +183,7 @@ void controllable_platform_tilt_from_mario(void) { f32 z = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform == o || gMarioStates[i].marioObj->platform == cur_obj_nearest_object_with_behavior(bhvControllablePlatformSub)) { x += gMarioStates[i].pos[0]; z += gMarioStates[i].pos[2]; diff --git a/src/game/behaviors/dorrie.inc.c b/src/game/behaviors/dorrie.inc.c index 3625267db..74001e4e7 100644 --- a/src/game/behaviors/dorrie.inc.c +++ b/src/game/behaviors/dorrie.inc.c @@ -136,6 +136,7 @@ void dorrie_act_raise_head(void) { for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform != o) { continue; } s32 dist = dist_between_objects(o, gMarioStates[0].marioObj); if (dist <= 780.0f) { continue; } diff --git a/src/game/behaviors/floating_platform.inc.c b/src/game/behaviors/floating_platform.inc.c index af16b85d1..2abb5617f 100644 --- a/src/game/behaviors/floating_platform.inc.c +++ b/src/game/behaviors/floating_platform.inc.c @@ -23,6 +23,7 @@ void floating_platform_act_0(void) { u8 playersTouched = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform == o) { x += gMarioStates[i].marioObj->oPosX; z += gMarioStates[i].marioObj->oPosZ; diff --git a/src/game/behaviors/platform_on_track.inc.c b/src/game/behaviors/platform_on_track.inc.c index 6aa588fcc..c27653b64 100644 --- a/src/game/behaviors/platform_on_track.inc.c +++ b/src/game/behaviors/platform_on_track.inc.c @@ -291,6 +291,7 @@ static void platform_on_track_rock_ski_lift(void) { struct Object* player = NULL; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform != o) { continue; } player = gMarioStates[i].marioObj; break; diff --git a/src/game/behaviors/seesaw_platform.inc.c b/src/game/behaviors/seesaw_platform.inc.c index c603bcf58..9c120ab0c 100644 --- a/src/game/behaviors/seesaw_platform.inc.c +++ b/src/game/behaviors/seesaw_platform.inc.c @@ -51,6 +51,7 @@ void bhv_seesaw_platform_update(void) { u8 playersTouched = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform == o) { x += gMarioStates[i].marioObj->oPosX; y += gMarioStates[i].marioObj->oPosY; diff --git a/src/game/behaviors/tilting_inverted_pyramid.inc.c b/src/game/behaviors/tilting_inverted_pyramid.inc.c index 7e3aff26f..0ef886414 100644 --- a/src/game/behaviors/tilting_inverted_pyramid.inc.c +++ b/src/game/behaviors/tilting_inverted_pyramid.inc.c @@ -87,6 +87,7 @@ void bhv_tilting_inverted_pyramid_loop(void) { u8 playersTouched = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { if (!is_player_active(&gMarioStates[i])) { continue; } + if (gMarioStates[i].marioObj == NULL) { continue; } if (gMarioStates[i].marioObj->platform != o) { continue; } x += gMarioStates[i].marioObj->oPosX; y += gMarioStates[i].marioObj->oPosY; @@ -135,7 +136,7 @@ void bhv_tilting_inverted_pyramid_loop(void) { o->oTiltingPyramidMarioOnPlatform = FALSE; } - // Approach the normals by 0.01f towards the new goal, then create a transform matrix and orient the object. + // Approach the normals by 0.01f towards the new goal, then create a transform matrix and orient the object. // Outside of the other conditionals since it needs to tilt regardless of whether Mario is on. o->oTiltingPyramidNormalX = approach_by_increment(dx, o->oTiltingPyramidNormalX, 0.01f); o->oTiltingPyramidNormalY = approach_by_increment(dy, o->oTiltingPyramidNormalY, 0.01f); diff --git a/src/game/level_update.c b/src/game/level_update.c index 91a0d4a48..9b01f28bc 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1508,7 +1508,7 @@ s32 run_current_play_mode() { s32 changeLevel = 0; s16 hookPlaymode = sCurrPlayMode; - if (smlua_call_event_hooks(HOOK_BEFORE_PLAY_MODE_RUN, sCurrPlayMode, &hookPlaymode)) { + if (smlua_call_event_hooks(HOOK_BEFORE_PLAY_MODE_UPDATE, sCurrPlayMode, &hookPlaymode)) { sCurrPlayMode = hookPlaymode; } @@ -1535,7 +1535,10 @@ s32 run_current_play_mode() { changeLevel = play_mode_frame_advance(); break; } - smlua_call_event_hooks(HOOK_ON_PLAY_MODE_RUN, sCurrPlayMode); + s32 hookChangeLevel = changeLevel; + if (smlua_call_event_hooks(HOOK_ON_PLAY_MODE_UPDATE, sCurrPlayMode, &hookChangeLevel)) { + changeLevel = hookChangeLevel; + } return changeLevel; } diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 5813341f1..19e2f77cb 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -3553,8 +3553,8 @@ char gSmluaConstants[] = "" "HOOK_ON_FIND_WATER_LEVEL=63\n" "HOOK_ON_FIND_POISON_GAS_LEVEL=64\n" "HOOK_ON_FIND_SURFACE_ON_RAY=65\n" -"HOOK_BEFORE_PLAY_MODE_RUN=66\n" -"HOOK_ON_PLAY_MODE_RUN=67\n" +"HOOK_BEFORE_PLAY_MODE_UPDATE=66\n" +"HOOK_ON_PLAY_MODE_UPDATE=67\n" "HOOK_MAX=68\n" "MAX_HOOKED_BEHAVIORS=1024\n" "HUD_DISPLAY_LIVES=0\n" diff --git a/src/pc/lua/smlua_hook_events.inl b/src/pc/lua/smlua_hook_events.inl index ced5b2434..3029c212c 100644 --- a/src/pc/lua/smlua_hook_events.inl +++ b/src/pc/lua/smlua_hook_events.inl @@ -64,5 +64,5 @@ SMLUA_EVENT_HOOK(HOOK_ON_FIND_FLOOR, _, f32 posX, f32 posY, f32 posZ, struct Sur SMLUA_EVENT_HOOK(HOOK_ON_FIND_WATER_LEVEL, _, f32 x, f32 z, f32 *waterLevel) // Manually defined hook SMLUA_EVENT_HOOK(HOOK_ON_FIND_POISON_GAS_LEVEL, _, f32 x, f32 z, f32 *gasLevel) // Manually defined hook SMLUA_EVENT_HOOK(HOOK_ON_FIND_SURFACE_ON_RAY, _, Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos) // Manually defined hook -SMLUA_EVENT_HOOK(HOOK_BEFORE_PLAY_MODE_RUN, HOOK_RETURN_NEVER, s16 playmode, OUTPUT s16 *overridePlaymode) -SMLUA_EVENT_HOOK(HOOK_ON_PLAY_MODE_RUN, HOOK_RETURN_NEVER, s16 playmode) \ No newline at end of file +SMLUA_EVENT_HOOK(HOOK_BEFORE_PLAY_MODE_UPDATE, HOOK_RETURN_NEVER, s16 playmode, OUTPUT s16 *overridePlaymode) +SMLUA_EVENT_HOOK(HOOK_ON_PLAY_MODE_UPDATE, HOOK_RETURN_NEVER, s16 playmode, OUTPUT s32 *changeLevel) \ No newline at end of file diff --git a/src/pc/lua/smlua_hook_events_autogen.inl b/src/pc/lua/smlua_hook_events_autogen.inl index ffcb8a164..6c67d7fe4 100644 --- a/src/pc/lua/smlua_hook_events_autogen.inl +++ b/src/pc/lua/smlua_hook_events_autogen.inl @@ -1864,12 +1864,12 @@ bool smlua_call_event_hooks_HOOK_ON_PACKET_BYTESTRING_RECEIVE(s32 modIndex, s32 return hookResult; } -bool smlua_call_event_hooks_HOOK_BEFORE_PLAY_MODE_RUN(s16 playmode, s16 *overridePlaymode) { +bool smlua_call_event_hooks_HOOK_BEFORE_PLAY_MODE_UPDATE(s16 playmode, s16 *overridePlaymode) { lua_State *L = gLuaState; if (L == NULL) { return false; } bool hookResult = false; - struct LuaHookedEvent *hook = &sHookedEvents[HOOK_BEFORE_PLAY_MODE_RUN]; + struct LuaHookedEvent *hook = &sHookedEvents[HOOK_BEFORE_PLAY_MODE_UPDATE]; for (int i = 0; i < hook->count; i++) { s32 prevTop = lua_gettop(L); @@ -1881,7 +1881,7 @@ bool smlua_call_event_hooks_HOOK_BEFORE_PLAY_MODE_RUN(s16 playmode, s16 *overrid // call the callback if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { - LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_BEFORE_PLAY_MODE_RUN], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); + LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_BEFORE_PLAY_MODE_UPDATE], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); continue; } hookResult = true; @@ -1896,12 +1896,12 @@ bool smlua_call_event_hooks_HOOK_BEFORE_PLAY_MODE_RUN(s16 playmode, s16 *overrid return hookResult; } -bool smlua_call_event_hooks_HOOK_ON_PLAY_MODE_RUN(s16 playmode) { +bool smlua_call_event_hooks_HOOK_ON_PLAY_MODE_UPDATE(s16 playmode, s32 *changeLevel) { lua_State *L = gLuaState; if (L == NULL) { return false; } bool hookResult = false; - struct LuaHookedEvent *hook = &sHookedEvents[HOOK_ON_PLAY_MODE_RUN]; + struct LuaHookedEvent *hook = &sHookedEvents[HOOK_ON_PLAY_MODE_UPDATE]; for (int i = 0; i < hook->count; i++) { s32 prevTop = lua_gettop(L); @@ -1912,12 +1912,17 @@ bool smlua_call_event_hooks_HOOK_ON_PLAY_MODE_RUN(s16 playmode) { lua_pushinteger(L, playmode); // call the callback - if (0 != smlua_call_hook(L, 1, 0, 0, hook->mod[i], hook->modFile[i])) { - LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_ON_PLAY_MODE_RUN], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i], hook->modFile[i])) { + LOG_LUA("Failed to call the callback for hook %s - '%s/%s'", sLuaHookedEventTypeName[HOOK_ON_PLAY_MODE_UPDATE], hook->mod[i]->relativePath, hook->modFile[i]->relativePath); continue; } hookResult = true; + // return changeLevel + if (lua_type(L, -1) == LUA_TNUMBER) { + *changeLevel = smlua_to_integer(L, -1); + } + lua_settop(L, prevTop); } return hookResult; diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 31102179d..700f6de8e 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -82,8 +82,8 @@ enum LuaHookedEventType { HOOK_ON_FIND_WATER_LEVEL, HOOK_ON_FIND_POISON_GAS_LEVEL, HOOK_ON_FIND_SURFACE_ON_RAY, - HOOK_BEFORE_PLAY_MODE_RUN, - HOOK_ON_PLAY_MODE_RUN, + HOOK_BEFORE_PLAY_MODE_UPDATE, + HOOK_ON_PLAY_MODE_UPDATE, HOOK_MAX, }; From 16c6c3da040ef01634dc5c68d3637b3ff25d9f5a Mon Sep 17 00:00:00 2001 From: EmeraldLockdown <86802223+EmeraldLoc@users.noreply.github.com> Date: Sat, 21 Mar 2026 17:29:33 -0500 Subject: [PATCH 3/3] Rename that func --- src/game/level_update.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/level_update.c b/src/game/level_update.c index 9b01f28bc..f47553751 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1504,7 +1504,7 @@ UNUSED static s32 play_mode_unused(void) { return 0; } -s32 run_current_play_mode() { +s32 update_current_play_mode() { s32 changeLevel = 0; s16 hookPlaymode = sCurrPlayMode; @@ -1769,7 +1769,7 @@ s32 update_level(void) { gCurrentArea->localAreaTimer++; } - changeLevel = run_current_play_mode(); + changeLevel = update_current_play_mode(); if (changeLevel) { reset_volume();