From 80f1d06ed8684cb88f6603e9e60fd01af0d948c4 Mon Sep 17 00:00:00 2001 From: Sunk <69110309+Sunketchupm@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:36:25 -0500 Subject: [PATCH] Create `hook_exclamation_box` in place of `set_exclamation_box_contents` (#524) * Revert set_exclamation_box_contents() In favor of the hook * Create `hook_exclamation_box` --- autogen/convert_constants.py | 2 +- autogen/convert_functions.py | 4 +- autogen/convert_structs.py | 5 +- autogen/lua_definitions/constants.lua | 4 +- autogen/lua_definitions/functions.lua | 9 +- autogen/lua_definitions/manual.lua | 14 +--- autogen/lua_definitions/structs.lua | 12 +-- docs/lua/functions-5.md | 18 ---- docs/lua/functions.md | 1 - docs/lua/guides/hooks.md | 46 ++++++++++ docs/lua/structs.md | 15 ---- src/game/behavior_actions.c | 6 -- src/game/behaviors/exclamation_box.inc.c | 38 +++++---- src/pc/lua/smlua.c | 3 - src/pc/lua/smlua_functions.c | 94 --------------------- src/pc/lua/smlua_functions_autogen.c | 16 ---- src/pc/lua/smlua_hooks.c | 102 +++++++++++++++++++++++ src/pc/lua/smlua_hooks.h | 3 + src/pc/lua/utils/smlua_obj_utils.c | 21 ----- src/pc/lua/utils/smlua_obj_utils.h | 13 --- 20 files changed, 184 insertions(+), 242 deletions(-) diff --git a/autogen/convert_constants.py b/autogen/convert_constants.py index 3993363c..b4bda912 100644 --- a/autogen/convert_constants.py +++ b/autogen/convert_constants.py @@ -339,7 +339,7 @@ def def_constant(processed_constant): return s def build_to_def(processed_files): - s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\n\n' + s = '-- AUTOGENERATED FOR CODE EDITORS --\n\n' with open(get_path(in_filename), 'r', newline='\n') as f: s += f.read() s += '\n' diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index f4e65acc..e329ca4c 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -105,7 +105,7 @@ override_disallowed_functions = { "src/game/obj_behaviors_2.c": [ "wiggler_jumped_on_attack_handler", "huge_goomba_weakly_attacked" ], "src/game/spawn_sound.c": [ "spawner" ], "src/game/level_info.h": [ "_name_table" ], - "src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field", "set_exclamation_box_new_contents", "get_exclamation_box_new_contents_pointer", "get_exclamation_box_new_contents_size" ], + "src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field" ], "src/game/camera.h": [ "update_camera", "init_camera", "stub_camera", "^reset_camera", "move_point_along_spline" ], "src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ], "src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown"], @@ -1071,7 +1071,7 @@ def def_function(function): def def_files(processed_files): - s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\n\n' + s = '-- AUTOGENERATED FOR CODE EDITORS --\n\n' for processed_file in processed_files: for function in processed_file['functions']: s += def_function(function) diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py index edca40b8..5983d53f 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -127,8 +127,7 @@ sLuaManuallyDefinedStructs = [{ 'structs': [ 'struct Vec3f { float x; float y; float z; }', 'struct Vec3s { s16 x; s16 y; s16 z; }', - 'struct Color { u8 r; u8 g; u8 b; }', - 'struct ExclamationBoxContents { u8 index; u8 unused; u8 firstByte; enum ModelExtendedId emodel; enum BehaviorId behaviorId; }' + 'struct Color { u8 r; u8 g; u8 b; }' ] }] @@ -629,7 +628,7 @@ def def_struct(struct): return s def def_structs(structs): - s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\n\n' + s = '-- AUTOGENERATED FOR CODE EDITORS --\n' for struct in structs: if struct['identifier'] in exclude_structs: diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 39340d5d..4176c3c1 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -1,6 +1,4 @@ --- AUTOGENERATED FOR CODE EDITORS -- ---- @meta ---- @diagnostic disable +-- AUTOGENERATED FOR CODE EDITORS -- math.randomseed(get_time()) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 823cc5cb..7087b4a1 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -1,6 +1,4 @@ --- AUTOGENERATED FOR CODE EDITORS -- ---- @meta ---- @diagnostic disable +-- AUTOGENERATED FOR CODE EDITORS -- --- @param id integer --- @return ObjectWarpNode @@ -9129,11 +9127,6 @@ function obj_set_vel(o, vx, vy, vz) -- ... end ---- @return nil -function restore_exclamation_box_original_contents() - -- ... -end - --- @param x number --- @param y number --- @param z number diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index 3f77c6da..4368a7c0 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -279,14 +279,8 @@ function level_script_parse(levelNum, func) -- ... end ---- @param contents ExclamationBoxContents[] ---- @return nil ---- The parameter should be a table containing several subtables with the following keys ---- - index: The index of the content (used by oBehParam2ndByte) ---- - unused: Unused ---- - firstByte: The spawned object's oBehParam's 1st byte ---- - emodel: The spawned object's model ---- - behaviorId: The spawned object's behavior ID -function set_exclamation_box_new_contents(contents) - -- ... +--- @param readFunc (fun(obj:Object):nil)? Called after the exclamation box spawns an object. Use this function to read the contents of the object that spawned. +--- @param writeFunc (fun(box:Object):Object)? Called when the exclamation box is about to spawn an object. Use this function to spawn a different object, and return the object for the read function to use. +function hook_exclamation_box(readFunc, writeFunc) + end \ No newline at end of file diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 2eca4d6b..2f81956d 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -1,7 +1,4 @@ --- AUTOGENERATED FOR CODE EDITORS -- ---- @meta ---- @diagnostic disable - +-- AUTOGENERATED FOR CODE EDITORS -- --- @class AnimInfo --- @field public animAccel integer @@ -2148,13 +2145,6 @@ --- @field public g integer --- @field public r integer ---- @class ExclamationBoxContents ---- @field public behaviorId BehaviorId ---- @field public emodel ModelExtendedId ---- @field public firstByte integer ---- @field public index integer ---- @field public unused integer - --- @class Pointer_integer --- @class Pointer_Trajectory --- @class Pointer_LevelScript diff --git a/docs/lua/functions-5.md b/docs/lua/functions-5.md index 96482dfb..a64cb047 100644 --- a/docs/lua/functions-5.md +++ b/docs/lua/functions-5.md @@ -2325,24 +2325,6 @@
-## [restore_exclamation_box_original_contents](#restore_exclamation_box_original_contents) - -### Lua Example -`restore_exclamation_box_original_contents()` - -### Parameters -- None - -### Returns -- None - -### C Prototype -`void restore_exclamation_box_original_contents(void);` - -[:arrow_up_small:](#) - -
- ## [set_whirlpools](#set_whirlpools) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 6b627f07..f5623e18 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1695,7 +1695,6 @@ - [obj_move_xyz](functions-5.md#obj_move_xyz) - [obj_set_model_extended](functions-5.md#obj_set_model_extended) - [obj_set_vel](functions-5.md#obj_set_vel) - - [restore_exclamation_box_original_contents](functions-5.md#restore_exclamation_box_original_contents) - [set_whirlpools](functions-5.md#set_whirlpools) - [spawn_non_sync_object](functions-5.md#spawn_non_sync_object) - [spawn_sync_object](functions-5.md#spawn_sync_object) diff --git a/docs/lua/guides/hooks.md b/docs/lua/guides/hooks.md index 36e05fa9..3f80c4d3 100644 --- a/docs/lua/guides/hooks.md +++ b/docs/lua/guides/hooks.md @@ -145,6 +145,52 @@ hook_event(HOOK_MARIO_UPDATE, mario_update)
+## [hook_exclamation_box](#hook_exclamation_box) + +Activated when an exclamation box breaks, allowing mods to take control over exclamation boxes. +- `readFunction` is called after the exclamation box breaks, allowing mods to read the object that spawned. + - No return value is necessary. +- `writeFunction` is called when the exclamation box breaks, allowing mods to override the spawned object. + - Returning the spawned object is highly recommended as it prevents spawning both the vanilla and new object at the same time. It also allows `readFunction` to function properly. + +### Parameters + +| Field | Type | +| ----- | ---- | +| readFunction | `Lua Function` ([Object](structs.md#Object)) | +| writeFunction | `Lua Function` ([Object](structs.md#Object)): [Object](structs.md#Object) | + +### Lua Example + +```lua +local objects_to_spawn = { + [0] = {id_bhvGoomba, E_MODEL_GOOMBA}, + [1] = {id_bhvKoopa, E_MODEL_KOOPA_WITH_SHELL}, + [2] = {id_bhvTenCoinsSpawn, E_MODEL_NONE}, + [3] = {id_bhvChainChomp, E_MODEL_CHAIN_CHOMP}, + [4] = {id_bhvHeaveHo, E_MODEL_HEAVE_HO}, + [5] = {id_bhvWingCap, E_MODEL_MARIOS_WING_CAP}, + [6] = {id_bhvKoopaShell, E_MODEL_KOOPA_SHELL}, + [7] = {id_bhvBoo, E_MODEL_BOO}, +} + +local function readFunction(obj) + if obj_has_behavior_id(obj, id_bhvFlame) ~= 0 then + print("FIREEEEEEEEE") + end +end + +---@param box Object +local function writeFunction(box) + local spawn_object = objects_to_spawn[box.oBehParams2ndByte] + return spawn_sync_object(spawn_object[1], spawn_object[2], box.oPosX, box.oPosY, box.oPosZ, nil) +end + +hook_exclamation_box(readFunction, writeFunction) +``` + +
+ ## [hook_mario_action](#hook_mario_action) `hook_mario_action()` allows Lua mods to create new actions or override existing ones. diff --git a/docs/lua/structs.md b/docs/lua/structs.md index 55a2deca..18190385 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -22,7 +22,6 @@ - [Cutscene](#Cutscene) - [CutsceneSplinePoint](#CutsceneSplinePoint) - [CutsceneVariable](#CutsceneVariable) -- [ExclamationBoxContents](#ExclamationBoxContents) - [FloorGeometry](#FloorGeometry) - [GlobalObjectAnimations](#GlobalObjectAnimations) - [GlobalObjectCollisionData](#GlobalObjectCollisionData) @@ -810,20 +809,6 @@
-## [ExclamationBoxContents](#ExclamationBoxContents) - -| Field | Type | Access | -| ----- | ---- | ------ | -| behaviorId | [enum BehaviorId](constants.md#enum-BehaviorId) | | -| emodel | [enum ModelExtendedId](constants.md#enum-ModelExtendedId) | | -| firstByte | `integer` | | -| index | `integer` | | -| unused | `integer` | | - -[:arrow_up_small:](#) - -
- ## [FloorGeometry](#FloorGeometry) | Field | Type | Access | diff --git a/src/game/behavior_actions.c b/src/game/behavior_actions.c index 03df7bd1..4aac7922 100644 --- a/src/game/behavior_actions.c +++ b/src/game/behavior_actions.c @@ -49,10 +49,6 @@ #include "pc/lua/utils/smlua_model_utils.h" #include "pc/lua/smlua_hooks.h" -#include "pc/lua/smlua.h" -#include "pc/lua/smlua_utils.h" -#include "pc/lua/utils/smlua_obj_utils.h" - #define o gCurrentObject struct WFRotatingPlatformData { @@ -78,7 +74,6 @@ struct Struct8032F698 { s16 unk4; }; -/* Moved to smlua_obj_utils.h struct Struct802C0DF0 { u8 unk0; u8 unk1; @@ -86,7 +81,6 @@ struct Struct802C0DF0 { u8 model; const BehaviorScript *behavior; }; -*/ struct Struct8032F754 { s32 unk0; diff --git a/src/game/behaviors/exclamation_box.inc.c b/src/game/behaviors/exclamation_box.inc.c index 109808f4..bfc38408 100644 --- a/src/game/behaviors/exclamation_box.inc.c +++ b/src/game/behaviors/exclamation_box.inc.c @@ -28,7 +28,7 @@ struct Struct802C0DF0 sExclamationBoxContents[] = { { 0, 0, 0, MODEL_MARIOS_WING { 12, 0, 3, MODEL_STAR, bhvSpawnedStar }, { 13, 0, 4, MODEL_STAR, bhvSpawnedStar }, { 14, 0, 5, MODEL_STAR, bhvSpawnedStar }, - { 255, 0, 0, 0, NULL } }; + { 99, 0, 0, 0, NULL } }; void bhv_rotating_exclamation_box_loop(void) { if (!o->parentObj || o->parentObj->oAction != 1) @@ -122,26 +122,33 @@ static s32 exclamation_replace_model(struct MarioState* m, s32 model) { } } -void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1, u8 size) { +void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { struct MarioState* marioState = nearest_mario_state_to_object(o); struct Object* player = marioState ? marioState->marioObj : NULL; - struct Object *sp1C = NULL; + struct Object *spawnedObject = NULL; if (o->oExclamationBoxForce) { return; } - for (u8 i = 0; i < size; i++) { + struct Object* luaSpawnedObject = NULL; + if ((luaSpawnedObject = smlua_call_exclamation_box_hook(o, true)) != NULL) { + (void *)smlua_call_exclamation_box_hook(luaSpawnedObject, false); + return; + } + + while (a0->unk0 != 99) { if (a1 == a0->unk0) { s32 model = exclamation_replace_model(marioState, a0->model); - sp1C = spawn_object(o, model, a0->behavior); - if (sp1C != NULL) { - sp1C->oVelY = 20.0f; - sp1C->oForwardVel = 3.0f; + spawnedObject = spawn_object(o, model, a0->behavior); + (void *)smlua_call_exclamation_box_hook(spawnedObject, false); + if (spawnedObject != NULL) { + spawnedObject->oVelY = 20.0f; + spawnedObject->oForwardVel = 3.0f; if (player) { - sp1C->oMoveAngleYaw = player->oMoveAngleYaw; - sp1C->globalPlayerIndex = player->globalPlayerIndex; + spawnedObject->oMoveAngleYaw = player->oMoveAngleYaw; + spawnedObject->globalPlayerIndex = player->globalPlayerIndex; } } o->oBehParams |= a0->unk2 << 24; @@ -150,13 +157,12 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1, u8 size) { // send non-star spawn events // stars cant be sent here to due jankiness in oBehParams - if (a0->behavior != smlua_override_behavior(bhvSpawnedStar) && sp1C != NULL) { + if (a0->behavior != smlua_override_behavior(bhvSpawnedStar) && spawnedObject != NULL) { // hack: if any other sync objects get spawned here we have to check for them - // problem: going to need to sync every object if (a0->behavior == smlua_override_behavior(bhvKoopaShell)) { - sync_object_set_id(sp1C); + sync_object_set_id(spawnedObject); } - struct Object* spawn_objects[] = { sp1C }; + struct Object* spawn_objects[] = { spawnedObject }; u32 models[] = { model }; network_send_spawn_objects(spawn_objects, models, 1); } @@ -167,9 +173,7 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1, u8 size) { } void exclamation_box_act_4(void) { - struct Struct802C0DF0 *newContents = get_exclamation_box_new_contents_pointer(); - u8 newContentsSize = get_exclamation_box_new_contents_size(); - exclamation_box_spawn_contents(newContents ? newContents : sExclamationBoxContents, o->oBehParams2ndByte, newContentsSize); + exclamation_box_spawn_contents(sExclamationBoxContents, o->oBehParams2ndByte); spawn_mist_particles_variable(0, 0, 46.0f); spawn_triangle_break_particles(20, 139, 0.3f, o->oAnimState); create_sound_spawner(SOUND_GENERAL_BREAK_BOX); diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 67f52868..8216c647 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -8,7 +8,6 @@ #include "pc/lua/utils/smlua_model_utils.h" #include "pc/lua/utils/smlua_level_utils.h" #include "pc/lua/utils/smlua_anim_utils.h" -#include "pc/lua/utils/smlua_obj_utils.h" #include "pc/djui/djui.h" lua_State* gLuaState = NULL; @@ -322,8 +321,6 @@ void smlua_shutdown(void) { smlua_model_util_clear(); smlua_level_util_reset(); smlua_anim_util_reset(); - restore_exclamation_box_original_contents(); - lua_State* L = gLuaState; if (L != NULL) { lua_close(L); diff --git a/src/pc/lua/smlua_functions.c b/src/pc/lua/smlua_functions.c index d401c974..18809025 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -14,7 +14,6 @@ #include "include/level_misc_macros.h" #include "include/macro_presets.h" #include "utils/smlua_anim_utils.h" -#include "utils/smlua_obj_utils.h" bool smlua_functions_valid_param_count(lua_State* L, int expected) { int top = lua_gettop(L); @@ -211,98 +210,6 @@ int smlua_func_network_send_to(lua_State* L) { return 1; } -int smlua_func_set_exclamation_box_new_contents(lua_State* L) { - if (L == NULL) { return 0; } - if (!smlua_functions_valid_param_count(L, 1)) { return 0; } - - static struct Struct802C0DF0 sExclamationBoxContentsArray[255]; - - u8 subtable_counter = 0; - if (lua_type(L, 1) != LUA_TTABLE) { - LOG_LUA("Failed to convert parameter 1 to table"); - return 0; - } - - lua_pushnil(L); // Set so lua_next() pops this off upon starting - // Enter main table - while (lua_next(L, 1) != 0) { - // key is index -2, value is index -1 - if (lua_type(L, -1) != LUA_TTABLE) { - LOG_LUA("Failed to find subtable\n"); - return 0; - } - - // Create an empty struct to put values in - struct Struct802C0DF0 sContents = { 0 }; - - int initialTop = lua_gettop(L); // Hopefully 3 - lua_pushnil(L); // Set so lua_next() pops this off upon starting - u8 elements_counter = 0; - // Special care is taken here, so any invalid subtables will error - while (lua_next(L, initialTop) != 0) { - int keyIndex = lua_gettop(L) - 1; - int valueIndex = lua_gettop(L) - 0; - - const char* key = smlua_to_string(L, keyIndex); - if (!gSmLuaConvertSuccess) { - LOG_LUA("Failed to convert key to string in subtable %u", subtable_counter); - return 0; - } - - const int value = smlua_to_integer(L, valueIndex); - if (!gSmLuaConvertSuccess) { - LOG_LUA("The key \"%s\" within subtable %u has a value that is not a number (Type: %u)", key, subtable_counter, lua_type(L, valueIndex)); - return 0; - } - - // Bad - if (!strcmp(key, "index")) { - sContents.unk0 = value; - elements_counter++; - lua_pop(L, 1); // pop value - } else if (!strcmp(key, "unused")) { - sContents.unk1 = value; - elements_counter++; - lua_pop(L, 1); // pop value - } else if (!strcmp(key, "firstByte")) { - sContents.unk2 = value; - elements_counter++; - lua_pop(L, 1); // pop value - } else if (!strcmp(key, "emodel")) { - u16 loadedModelId = smlua_model_util_load(value); - sContents.model = loadedModelId; - elements_counter++; - lua_pop(L, 1); // pop value - } else if (!strcmp(key, "behaviorId")) { - sContents.behavior = get_behavior_from_id(value); - elements_counter++; - lua_pop(L, 1); // pop value - } else { - LOG_LUA("The key \"%s\" in subtable %u is invalid", key, subtable_counter); - return 0; - } - } - - if (elements_counter != 5) { - LOG_LUA("Invalid elements count in subtable %u (There should be 5)", subtable_counter); - return 0; - } - - // Element 254 will not be set - if (subtable_counter < 254) { - sExclamationBoxContentsArray[subtable_counter] = sContents; - subtable_counter++; - } - - lua_pop(L, 1); // pop key - } - lua_pop(L, 1); // pop key - - set_exclamation_box_new_contents(sExclamationBoxContentsArray, subtable_counter); - - return 1; -} - ////////////// // Textures // ////////////// @@ -840,5 +747,4 @@ void smlua_bind_functions(void) { 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); smlua_bind_function(L, "smlua_anim_util_register_animation", smlua_func_smlua_anim_util_register_animation); - smlua_bind_function(L, "set_exclamation_box_new_contents", smlua_func_set_exclamation_box_new_contents); } diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index df3ee83e..a6b64373 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -29939,21 +29939,6 @@ int smlua_func_obj_set_vel(lua_State* L) { return 1; } -int smlua_func_restore_exclamation_box_original_contents(UNUSED lua_State* L) { - if (L == NULL) { return 0; } - - int top = lua_gettop(L); - if (top != 0) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "restore_exclamation_box_original_contents", 0, top); - return 0; - } - - - restore_exclamation_box_original_contents(); - - return 1; -} - int smlua_func_set_whirlpools(lua_State* L) { if (L == NULL) { return 0; } @@ -32625,7 +32610,6 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "obj_move_xyz", smlua_func_obj_move_xyz); smlua_bind_function(L, "obj_set_model_extended", smlua_func_obj_set_model_extended); smlua_bind_function(L, "obj_set_vel", smlua_func_obj_set_vel); - smlua_bind_function(L, "restore_exclamation_box_original_contents", smlua_func_restore_exclamation_box_original_contents); smlua_bind_function(L, "set_whirlpools", smlua_func_set_whirlpools); smlua_bind_function(L, "spawn_non_sync_object", smlua_func_spawn_non_sync_object); smlua_bind_function(L, "spawn_sync_object", smlua_func_spawn_sync_object); diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index 5ae08fd1..11b34cd3 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -1752,6 +1752,107 @@ int smlua_hook_on_sync_table_change(lua_State* L) { return 1; } + //////////////////////////// + // hooked exclamation box // +//////////////////////////// + +struct LuaHookedExclamationBox { + int readFuncReference; + int writeFuncReference; + struct Mod* mod; +}; + +#define MAX_HOOKED_EXCLAMATION_BOXES 255 // Way more than needed, but better safe than sorry + +static struct LuaHookedExclamationBox sHookedExclamationBoxes[MAX_HOOKED_EXCLAMATION_BOXES] = { 0 }; +static int sHookedExclamationBoxesCount = 0; + +// Bind to lua +int smlua_hook_exclamation_box(lua_State* L) { + if (L == NULL) { return 0; } + if (!smlua_functions_valid_param_count(L, 2)) { return 0; } + + if (gLuaLoadingMod == NULL) { + LOG_LUA_LINE("hook_exclamation_box() can only be called on load."); + return 0; + } + + if (sHookedBehaviorsCount > MAX_HOOKED_EXCLAMATION_BOXES) { + LOG_LUA_LINE("hook_exclamation_box() calls exceeded maximum references"); + return 0; + } + + int readReference = 0; + int readReferenceType = lua_type(L, 1); + if (readReferenceType == LUA_TNIL) { + // nothing + } else if (readReferenceType == LUA_TFUNCTION) { + // get reference + lua_pushvalue(L, 1); + readReference = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + LOG_LUA_LINE("Hook exclamation box: tried to reference non-function for read function"); + return 0; + } + + int writeReference = 0; + int writeReferenceType = lua_type(L, 2); + if (writeReferenceType == LUA_TNIL) { + // nothing + } else if (writeReferenceType == LUA_TFUNCTION) { + // get reference + lua_pushvalue(L, 2); + writeReference = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + LOG_LUA_LINE("Hook exclamation box: tried to reference non-function for write function"); + return 0; + } + + struct LuaHookedExclamationBox* hooked = &sHookedExclamationBoxes[sHookedExclamationBoxesCount]; + hooked->readFuncReference = readReference; + hooked->writeFuncReference = writeReference; + hooked->mod = gLuaActiveMod; + + if (!gSmLuaConvertSuccess) { return 0; } + sHookedBehaviorsCount++; + return 1; +} + +// Called from the exclamation boxes +struct Object* smlua_call_exclamation_box_hook(struct Object* obj, bool write) { + lua_State* L = gLuaState; + if (L == NULL) { return NULL; } + for (int i = 0; i < sHookedBehaviorsCount; i++) { + struct LuaHookedExclamationBox* hook = &sHookedExclamationBoxes[i]; + + // Push 2 potential callbacks + int reference = write ? hook->writeFuncReference : hook->readFuncReference; + lua_rawgeti(L, LUA_REGISTRYINDEX, reference); + + // push object + smlua_push_object(L, LOT_OBJECT, obj); + + // call the callback + if (reference != 0 && 0 != smlua_call_hook(L, 1, 1, 0, hook->mod)) { + LOG_LUA("Failed to call the exclamation box callback: %s", (write ? "writeFunction" : "readFunction")); + continue; + } + + // output the return value + struct Object* returnObject = NULL; + if (write) { + returnObject = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT); + } + lua_pop(L, 1); + + if (!gSmLuaConvertSuccess) { return NULL; } + + return returnObject; + } + + return NULL; +} + ////////// // misc // @@ -1828,4 +1929,5 @@ void smlua_bind_hooks(void) { smlua_bind_function(L, "hook_on_sync_table_change", smlua_hook_on_sync_table_change); smlua_bind_function(L, "hook_behavior", smlua_hook_behavior); smlua_bind_function(L, "update_chat_command_description", smlua_update_chat_command_description); + smlua_bind_function(L, "hook_exclamation_box", smlua_hook_exclamation_box); } diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 28b47e20..7b84ea8b 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -133,6 +133,9 @@ bool smlua_call_event_hooks_mario_param_and_int_ret_int(enum LuaHookedEventType 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); +int smlua_hook_exclamation_box(lua_State* L); +struct Object* smlua_call_exclamation_box_hook(struct Object* obj, bool write); + enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior); const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior); const BehaviorScript* smlua_get_hooked_behavior_from_id(enum BehaviorId id, bool returnOriginal); diff --git a/src/pc/lua/utils/smlua_obj_utils.c b/src/pc/lua/utils/smlua_obj_utils.c index 1bda952d..f87752a4 100644 --- a/src/pc/lua/utils/smlua_obj_utils.c +++ b/src/pc/lua/utils/smlua_obj_utils.c @@ -407,27 +407,6 @@ void set_whirlpools(f32 x, f32 y, f32 z, s16 strength, s16 area, s32 index) { gAreas[area].whirlpools[index]->strength = strength; } -struct Struct802C0DF0 *newContents = NULL; -u8 newContentsSize = 16; - -struct Struct802C0DF0* get_exclamation_box_new_contents_pointer(void) { - return newContents; -} - -u8 get_exclamation_box_new_contents_size(void) { - return newContentsSize; -} - -void set_exclamation_box_new_contents(struct Struct802C0DF0 contents[], u8 size) { - newContents = contents; - newContentsSize = size; -} - -void restore_exclamation_box_original_contents(void) { - newContents = NULL; - newContentsSize = 16; -} - #ifdef DEVELOPMENT void obj_randomize(struct Object* o) { if (!o) { return; } diff --git a/src/pc/lua/utils/smlua_obj_utils.h b/src/pc/lua/utils/smlua_obj_utils.h index 5fae98bc..48b0963f 100644 --- a/src/pc/lua/utils/smlua_obj_utils.h +++ b/src/pc/lua/utils/smlua_obj_utils.h @@ -5,14 +5,6 @@ #include "smlua_model_utils.h" #include "game/object_list_processor.h" -struct Struct802C0DF0 { - u8 unk0; // Index - u8 unk1; // Unused - u8 unk2; // oBehParams1stByte - u16 model; - const BehaviorScript *behavior; -}; - struct Object* spawn_sync_object(enum BehaviorId behaviorId, enum ModelExtendedId modelId, f32 x, f32 y, f32 z, LuaFunction objSetupFunction); struct Object* spawn_non_sync_object(enum BehaviorId behaviorId, enum ModelExtendedId modelId, f32 x, f32 y, f32 z, LuaFunction objSetupFunction); @@ -65,9 +57,4 @@ void obj_move_xyz(struct Object *o, f32 dx, f32 dy, f32 dz); void set_whirlpools(f32 x, f32 y, f32 z, s16 strength, s16 area, s32 index); -struct Struct802C0DF0* get_exclamation_box_new_contents_pointer(void); -u8 get_exclamation_box_new_contents_size(void); -void set_exclamation_box_new_contents(struct Struct802C0DF0 contents[], u8 size); -void restore_exclamation_box_original_contents(void); - #endif