diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 8c2200a7..492641aa 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -9104,7 +9104,10 @@ HOOK_ON_HUD_RENDER_BEHIND = 36 HOOK_ON_COLLIDE_LEVEL_BOUNDS = 37 --- @type LuaHookedEventType -HOOK_MAX = 38 +HOOK_MIRROR_MARIO_RENDER = 38 + +--- @type LuaHookedEventType +HOOK_MAX = 39 --- @class HudDisplayFlags diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 8d37c794..55c9725e 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -3253,7 +3253,8 @@ | HOOK_DIALOG_SOUND | 35 | | HOOK_ON_HUD_RENDER_BEHIND | 36 | | HOOK_ON_COLLIDE_LEVEL_BOUNDS | 37 | -| HOOK_MAX | 38 | +| HOOK_MIRROR_MARIO_RENDER | 38 | +| HOOK_MAX | 39 | [:arrow_up_small:](#) diff --git a/docs/lua/guides/hooks.md b/docs/lua/guides/hooks.md index a1f92692..e72e015e 100644 --- a/docs/lua/guides/hooks.md +++ b/docs/lua/guides/hooks.md @@ -117,12 +117,15 @@ The lua functions sent to `hook_event()` will be automatically called by SM64 wh | HOOK_ON_CHAT_MESSAGE | Called when a chat message gets sent. Return `false` to prevent the message from being sent | [MarioState](structs.md#MarioState) messageSender, `string` messageSent | | HOOK_OBJECT_SET_MODEL | Called when a behavior changes models. Also runs when a behavior spawns | [Object](structs.md#Object) obj, `integer` modelID | | HOOK_CHARACTER_SOUND | Called when mario retrieves a character sound to play, return a character sound or `0` to override it | [MarioState](structs.md#MarioState) mario, [enum CharacterSound](constants.md#enum-CharacterSound) characterSound | -| HOOK_JOINED_GAME | Called when the local player finishes the join process (if the player isn't the host) | None | | HOOK_BEFORE_SET_MARIO_ACTION | Called before Mario's action changes Return an action to change the incoming action or `1` to cancel the action change | [MarioState](structs.md#MarioState) mario, `integer` incomingAction | +| HOOK_JOINED_GAME | Called when the local player finishes the join process (if the player isn't the host) | None | | HOOK_ON_OBJECT_ANIM_UPDATE | Called when an object's animation is updated | [Object](structs.md#Object) objNode | | HOOK_ON_DIALOG | Called when a dialog appears. Return `false` to prevent it from appearing | `integer` dialogId | | HOOK_ON_EXIT | Called before the game shuts down | None | | HOOK_DIALOG_SOUND | Called when a dialog box sound is going to play, return a `DS_*` constant to override the sound | `integer` dialogSound | +| HOOK_ON_HUD_RENDER_BEHIND | Called when the HUD is being rendered, every HUD call in this hook renders behind the vanilla HUD | None | +| HOOK_ON_COLLIDE_LEVEL_BOUNDS | Called when a mario collides with the level boundaries | [MarioState](structs.md#MarioState)mario | +| HOOK_MIRROR_MARIO_RENDER | Called when a Mirror Mario is rendered. | [GraphNodeObject](structs.md#GraphNodeObject) mirrorMario | `integer` mirrorMarioIndex | ### Parameters diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 9671282c..0dbfa78b 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -25,6 +25,7 @@ #include "hardcoded.h" #include "sound_init.h" #include "pc/network/network.h" +#include "pc/lua/smlua_hooks.h" #define TOAD_STAR_1_REQUIREMENT gBehaviorValues.ToadStar1Requirement #define TOAD_STAR_2_REQUIREMENT gBehaviorValues.ToadStar2Requirement @@ -705,6 +706,8 @@ Gfx* geo_render_mirror_mario(s32 callContext, struct GraphNode* node, UNUSED Mat gMirrorMario[i].scale[0] *= -1.0f; // TODO: does rendering the mirror room still crash? gMirrorMario[i].node.flags |= GRAPH_RENDER_ACTIVE; + + smlua_call_event_hooks_graph_node_object_and_int_param(HOOK_MIRROR_MARIO_RENDER, &gMirrorMario[i], i); } else { gMirrorMario[i].node.flags &= ~GRAPH_RENDER_ACTIVE; } diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index 7b68f04e..ef80c265 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -604,54 +604,47 @@ void smlua_cobject_init_globals(void) { } { - smlua_push_object(L, LOT_GLOBALTEXTURES, &gGlobalTextures); - lua_setglobal(L, "gTextures"); + lua_newtable(L); + int t = lua_gettop(gLuaState); + for (s32 i = 0; i < PALETTE_PRESET_MAX; i++) { + lua_pushinteger(L, i); + smlua_push_object(L, LOT_PLAYERPALETTE, &gPalettePresets[i]); + lua_settable(L, t); + } + lua_setglobal(L, "gPalettePresets"); } - { - smlua_push_object(L, LOT_GLOBALOBJECTANIMATIONS, &gGlobalObjectAnimations); - lua_setglobal(L, "gObjectAnimations"); - } +#define EXPOSE_GLOBAL(lot, ptr) \ + { \ + smlua_push_object(L, lot, &ptr); \ + lua_setglobal(L, #ptr); \ + } \ - { - smlua_push_object(L, LOT_GLOBALOBJECTCOLLISIONDATA, &gGlobalObjectCollisionData); - lua_setglobal(L, "gGlobalObjectCollisionData"); - } +#define EXPOSE_GLOBAL_WITH_NAME(lot, ptr, name) \ + { \ + smlua_push_object(L, lot, &ptr); \ + lua_setglobal(L, name); \ + } \ - { - smlua_push_object(L, LOT_LAKITUSTATE, &gLakituState); - lua_setglobal(L, "gLakituState"); - } + EXPOSE_GLOBAL_WITH_NAME(LOT_GLOBALTEXTURES, gGlobalTextures, "gTextures"); - { - smlua_push_object(L, LOT_SERVERSETTINGS, &gServerSettings); - lua_setglobal(L, "gServerSettings"); - } + EXPOSE_GLOBAL_WITH_NAME(LOT_GLOBALOBJECTANIMATIONS, gGlobalObjectAnimations, "gObjectAnimations"); - { - smlua_push_object(L, LOT_NAMETAGSSETTINGS, &gNametagsSettings); - lua_setglobal(L, "gNametagsSettings"); - } + EXPOSE_GLOBAL(LOT_PAINTINGVALUES, gPaintingValues); - { - smlua_push_object(L, LOT_LEVELVALUES, &gLevelValues); - lua_setglobal(L, "gLevelValues"); - } + EXPOSE_GLOBAL(LOT_GLOBALOBJECTCOLLISIONDATA, gGlobalObjectCollisionData); // I wish we named this gObjectCollisionData - { - smlua_push_object(L, LOT_BEHAVIORVALUES, &gBehaviorValues); - lua_setglobal(L, "gBehaviorValues"); - } + EXPOSE_GLOBAL(LOT_LEVELVALUES, gLevelValues); - { - smlua_push_object(L, LOT_PAINTINGVALUES, &gPaintingValues); - lua_setglobal(L, "gPaintingValues"); - } + EXPOSE_GLOBAL(LOT_BEHAVIORVALUES, gBehaviorValues); - { - smlua_push_object(L, LOT_FIRSTPERSONCAMERA, &gFirstPersonCamera); - lua_setglobal(L, "gFirstPersonCamera"); - } + EXPOSE_GLOBAL(LOT_FIRSTPERSONCAMERA, gFirstPersonCamera); + + EXPOSE_GLOBAL(LOT_LAKITUSTATE, gLakituState); + + EXPOSE_GLOBAL(LOT_SERVERSETTINGS, gServerSettings); + + EXPOSE_GLOBAL(LOT_NAMETAGSSETTINGS, gNametagsSettings); } void smlua_cobject_init_per_file_globals(const char* path) { diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 5e81d959..c4f0b2c6 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -3226,7 +3226,8 @@ char gSmluaConstants[] = "" "HOOK_DIALOG_SOUND = 35\n" "HOOK_ON_HUD_RENDER_BEHIND = 36\n" "HOOK_ON_COLLIDE_LEVEL_BOUNDS = 37\n" -"HOOK_MAX = 38\n" +"HOOK_MIRROR_MARIO_RENDER = 38\n" +"HOOK_MAX = 39\n" "ACTION_HOOK_EVERY_FRAME = 0\n" "ACTION_HOOK_GRAVITY = 1\n" "ACTION_HOOK_MAX = 2\n" diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 59f29d88..a72855ec 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -916,6 +916,28 @@ bool smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(enum LuaHookedEv return false; } +void smlua_call_event_hooks_graph_node_object_and_int_param(enum LuaHookedEventType hookType, struct GraphNodeObject* node, s32 param) { + lua_State* L = gLuaState; + if (L == NULL) { return; } + struct LuaHookedEvent* hook = &sHookedEvents[hookType]; + for (int i = 0; i < hook->count; i++) { + // push the callback onto the stack + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference[i]); + + // push graph node object + smlua_push_object(L, LOT_GRAPHNODEOBJECT, node); + + // push param + lua_pushinteger(L, param); + + // call the callback + if (0 != smlua_call_hook(L, 2, 0, 0, hook->mod[i])) { + LOG_LUA("Failed to call the callback: %u", hookType); + continue; + } + } +} + //////////////////// // hooked actions // //////////////////// @@ -1554,7 +1576,7 @@ s32 sort_alphabetically(const void *a, const void *b) { } char** smlua_get_chat_player_list(void) { - char* playerNames[MAX_PLAYERS] = { NULL }; + char* playerNames[MAX_PLAYERS] = { NULL }; s32 playerCount = 0; for (s32 i = 0; i < MAX_PLAYERS; i++) { @@ -1667,7 +1689,7 @@ bool smlua_maincommand_exists(const char* maincommand) { free(commands[j]); } free(commands); - + return result; } @@ -1692,7 +1714,7 @@ bool smlua_subcommand_exists(const char* maincommand, const char* subcommand) { free(subcommands[j]); } free(subcommands); - + return result; } diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 4700d018..9eb2903a 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -49,6 +49,7 @@ enum LuaHookedEventType { HOOK_DIALOG_SOUND, HOOK_ON_HUD_RENDER_BEHIND, HOOK_ON_COLLIDE_LEVEL_BOUNDS, + HOOK_MIRROR_MARIO_RENDER, HOOK_MAX, }; @@ -91,6 +92,7 @@ static const char* LuaHookedEventTypeName[] = { "HOOK_DIALOG_SOUND", "HOOK_ON_HUD_RENDER_BEHIND", "HOOK_ON_COLLIDE_LEVEL_BOUNDS", + "HOOK_MIRROR_MARIO_RENDER", "HOOK_MAX" }; @@ -136,6 +138,7 @@ void smlua_call_event_hooks_mario_action_params_ret_int(enum LuaHookedEventType void smlua_call_event_hooks_mario_param_and_int_ret_bool(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, bool* returnValue); bool smlua_call_event_hooks_mario_param_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, s32* returnValue); bool smlua_call_event_hooks_mario_param_and_int_and_int_ret_int(enum LuaHookedEventType hookType, struct MarioState* m, s32 param, u32 args, s32* returnValue); +void smlua_call_event_hooks_graph_node_object_and_int_param(enum LuaHookedEventType hookType, struct GraphNodeObject* node, s32 param); enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior); const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior);