diff --git a/docs/lua/hooks.md b/docs/lua/hooks.md index 3a49cf1f..329904bb 100644 --- a/docs/lua/hooks.md +++ b/docs/lua/hooks.md @@ -102,7 +102,7 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh | HOOK_ON_SYNC_VALID | Called when the current area is synchronized | None | | HOOK_ON_OBJECT_UNLOAD | Called when any object is unloaded | [Object](structs.md#Object) unloadedObject | | HOOK_ON_SYNC_OBJECT_UNLOAD | Called when any networked object is unloaded | [Object](structs.md#Object) unloadedObject | -| HOOK_ON_PAUSE_EXIT | Called when the local player exits through the pause screen | `boolean` usedExitToCastle | +| HOOK_ON_PAUSE_EXIT | Called when the local player exits through the pause screen, return `false` to prevent the exit | `boolean` usedExitToCastle | ### Parameters diff --git a/mods/hide-and-seek.lua b/mods/hide-and-seek.lua index 629015d6..7837f8e9 100644 --- a/mods/hide-and-seek.lua +++ b/mods/hide-and-seek.lua @@ -416,6 +416,7 @@ function on_pause_exit(exitToCastle) s.seeking = true network_player_set_description(gNetworkPlayers[0], "seeker", 255, 64, 64, 255) end + return true end function allow_pvp_attack(m1, m2) diff --git a/src/game/level_update.c b/src/game/level_update.c index 99c88b03..7d0f8a44 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1162,20 +1162,26 @@ s32 play_mode_paused(void) { gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN; set_play_mode(PLAY_MODE_NORMAL); } else if (gPauseScreenMode == 2) { - level_trigger_warp(&gMarioStates[0], WARP_OP_EXIT); - set_play_mode(PLAY_MODE_NORMAL); - smlua_call_event_hooks_bool_param(HOOK_ON_PAUSE_EXIT, false); - } else if (gPauseScreenMode == 3) { - // Exit level - if (gDebugLevelSelect) { - fade_into_special_warp(-9, 1); - } else { - initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); - fade_into_special_warp(0, 0); - gSavedCourseNum = COURSE_NONE; + bool allowExit = true; + smlua_call_event_hooks_bool_param_ret_bool(HOOK_ON_PAUSE_EXIT, false, &allowExit); + if (allowExit) { + level_trigger_warp(&gMarioStates[0], WARP_OP_EXIT); + set_play_mode(PLAY_MODE_NORMAL); + } + } else if (gPauseScreenMode == 3) { + bool allowExit = true; + smlua_call_event_hooks_bool_param_ret_bool(HOOK_ON_PAUSE_EXIT, true, &allowExit); + if (allowExit) { + // Exit level + if (gDebugLevelSelect) { + fade_into_special_warp(-9, 1); + } else { + initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); + fade_into_special_warp(0, 0); + gSavedCourseNum = COURSE_NONE; + } + set_play_mode(PLAY_MODE_CHANGE_LEVEL); } - set_play_mode(PLAY_MODE_CHANGE_LEVEL); - smlua_call_event_hooks_bool_param(HOOK_ON_PAUSE_EXIT, true); } /* else if (gPauseScreenMode == 4) { // We should only be getting "int 4" to here initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0); diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 37a9fd38..cf8e5076 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -95,6 +95,34 @@ void smlua_call_event_hooks_bool_param(enum LuaHookedEventType hookType, bool va } } +void smlua_call_event_hooks_bool_param_ret_bool(enum LuaHookedEventType hookType, bool value, bool* returnValue) { + lua_State* L = gLuaState; + if (L == NULL) { return; } + struct LuaHookedEvent* hook = &sHookedEvents[hookType]; + 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 value + lua_pushboolean(L, value); + + // call the callback + if (0 != smlua_call_hook(L, 1, 1, 0, hook->mod[i])) { + LOG_LUA("Failed to call the callback: %u, %s", hookType, lua_tostring(L, -1)); + smlua_logline(); + continue; + } + + // output the return value + if (lua_type(L, -1) == LUA_TBOOLEAN) { + *returnValue = smlua_to_boolean(L, -1); + } + lua_settop(L, prevTop); + } +} + void smlua_call_event_hooks_mario_param(enum LuaHookedEventType hookType, struct MarioState* m) { lua_State* L = gLuaState; if (L == NULL) { return; } @@ -152,6 +180,8 @@ void smlua_call_event_hooks_mario_params_ret_bool(enum LuaHookedEventType hookTy if (L == NULL) { return; } struct LuaHookedEvent* hook = &sHookedEvents[hookType]; 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]); @@ -175,8 +205,10 @@ void smlua_call_event_hooks_mario_params_ret_bool(enum LuaHookedEventType hookTy } // output the return value - *returnValue = smlua_to_boolean(L, -1); - lua_pop(L, 1); + if (lua_type(L, -1) == LUA_TBOOLEAN) { + *returnValue = smlua_to_boolean(L, -1); + } + lua_settop(L, prevTop); } } diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index b3391b04..ef1e623a 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -50,6 +50,7 @@ extern u32 gLuaMarioActionIndex; void smlua_call_event_hooks(enum LuaHookedEventType hookType); void smlua_call_event_hooks_bool_param(enum LuaHookedEventType hookType, bool value); +void smlua_call_event_hooks_bool_param_ret_bool(enum LuaHookedEventType hookType, bool value, bool* returnValue); void smlua_call_event_hooks_mario_param(enum LuaHookedEventType hookType, struct MarioState* m); void smlua_call_event_hooks_mario_params(enum LuaHookedEventType hookType, struct MarioState* m1, struct MarioState* m2); void smlua_call_event_hooks_mario_params_ret_bool(enum LuaHookedEventType hookType, struct MarioState* m1, struct MarioState* m2, bool* returnValue);