From a85c8dbbf87d9af1ca0ddc47acf2d1c31fd08070 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 eb2f59c0..26a1beab 100644
--- a/autogen/convert_constants.py
+++ b/autogen/convert_constants.py
@@ -340,7 +340,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') as f:
s += f.read()
s += '\n'
diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py
index 14c94bee..36a57274 100644
--- a/autogen/convert_functions.py
+++ b/autogen/convert_functions.py
@@ -106,7 +106,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"],
@@ -1233,7 +1233,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 ca51fb15..f92c8505 100644
--- a/autogen/convert_structs.py
+++ b/autogen/convert_structs.py
@@ -131,8 +131,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; }'
]
}]
@@ -633,7 +632,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 492641aa..708392b5 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 fd31f87b..9d96d082 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
@@ -9224,11 +9222,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 6a80e544..ca8f2623 100644
--- a/autogen/lua_definitions/manual.lua
+++ b/autogen/lua_definitions/manual.lua
@@ -308,14 +308,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 79bbe6e3..9cb2c9df 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
@@ -2186,13 +2183,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 ca93cd4e..a13abfa9 100644
--- a/docs/lua/functions-5.md
+++ b/docs/lua/functions-5.md
@@ -2463,24 +2463,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 aac48651..8e16a688 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -1723,7 +1723,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 e72e015e..a6dc0225 100644
--- a/docs/lua/guides/hooks.md
+++ b/docs/lua/guides/hooks.md
@@ -149,6 +149,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 7a85801e..a6c2ff9c 100644
--- a/docs/lua/structs.md
+++ b/docs/lua/structs.md
@@ -24,7 +24,6 @@
- [CutsceneVariable](#CutsceneVariable)
- [DateTime](#DateTime)
- [DjuiColor](#DjuiColor)
-- [ExclamationBoxContents](#ExclamationBoxContents)
- [FirstPersonCamera](#FirstPersonCamera)
- [FloorGeometry](#FloorGeometry)
- [GlobalObjectAnimations](#GlobalObjectAnimations)
@@ -843,20 +842,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:](#)
-
-
-
## [FirstPersonCamera](#FirstPersonCamera)
| 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 7ccba388..05bc963a 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 //
//////////////
@@ -910,5 +817,4 @@ void smlua_bind_functions(void) {
smlua_bind_function(L, "texture_override_reset", smlua_func_texture_override_reset);
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 6a72fdf0..68b56a18 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -30219,21 +30219,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; }
@@ -32924,7 +32909,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 a72855ec..ed5517cf 100644
--- a/src/pc/lua/smlua_hooks.c
+++ b/src/pc/lua/smlua_hooks.c
@@ -1777,6 +1777,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 //
@@ -1853,4 +1954,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 9eb2903a..80a1c662 100644
--- a/src/pc/lua/smlua_hooks.h
+++ b/src/pc/lua/smlua_hooks.h
@@ -140,6 +140,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 c0ed5c4e..9c27003e 100644
--- a/src/pc/lua/utils/smlua_obj_utils.c
+++ b/src/pc/lua/utils/smlua_obj_utils.c
@@ -410,27 +410,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