From c428612a9e19c688d8841f7fc3c3a88314eeb140 Mon Sep 17 00:00:00 2001 From: Sunk <69110309+Sunketchupm@users.noreply.github.com> Date: Tue, 18 Jul 2023 18:18:02 -0400 Subject: [PATCH] Add set_exclamation_box_contents() (#445) * Properly set Mario's y vel to 0 on popping * Change 0 to 0.0f, just in case * Re-introduce a few vanilla bugs under gBehaviorValues The Shell Mario glitch was patched as a side effect to patching a different bug, but several romhacks use it so I need it back. The ability to collect multiple normal caps at once is needed for hat-in-hand using the hat factory glitch. * Fix Shell Mario fix Found the actual reason why the glitch doesn't work and figured that this change shouldn't affect anything else, so I removed its entry from gBehaviorValues. * Add InfiniteRenderDistance to gBehaviorValues I'm well aware that disabling the infinite render distance will be very desync prone, however a few glitches, most notably cloning and chuckya double jump, need objects load and unload from render distance. * Allow mods to disable the camera centering from romhack camera * Allow mods to disable romhack camera centering Done again * Update on network shutdown * Remove a line which I have no idea why it returned * Add set_exclamation_box_contents() No way this is memory safe or even well made but I did what I could * Added (most of) peachy's suggestions Still need to figure out how to stop the game from reading further than the size of the array without using a hardcoded number * Added more of peachy's suggestions I figured a good way to cap how far the exclamation box reads is to pass in the length of the array as well --- 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 | 12 +++ autogen/lua_definitions/structs.lua | 12 ++- docs/lua/functions-5.md | 18 +++++ docs/lua/functions.md | 1 + docs/lua/structs.md | 15 ++++ src/game/behavior_actions.c | 6 ++ src/game/behaviors/exclamation_box.inc.c | 11 ++- src/pc/lua/smlua.c | 3 + src/pc/lua/smlua_functions.c | 94 ++++++++++++++++++++++++ src/pc/lua/smlua_functions_autogen.c | 16 ++++ src/pc/lua/utils/smlua_obj_utils.c | 21 ++++++ src/pc/lua/utils/smlua_obj_utils.h | 13 ++++ 17 files changed, 234 insertions(+), 12 deletions(-) diff --git a/autogen/convert_constants.py b/autogen/convert_constants.py index ebe19add..020e0312 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\n' + s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\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 d8e381ba..73fc9370 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -102,7 +102,7 @@ override_disallowed_functions = { "src/game/obj_behaviors.c": [ "debug_" ], "src/game/obj_behaviors_2.c": [ "wiggler_jumped_on_attack_handler", "huge_goomba_weakly_attacked" ], "src/game/spawn_sound.c": [ "spawner" ], - "src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field" ], + "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/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"], @@ -1067,7 +1067,7 @@ def def_function(function): def def_files(processed_files): - s = '-- AUTOGENERATED FOR CODE EDITORS --\n\n' + s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\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 a633aa09..65343d78 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -123,7 +123,8 @@ 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 Color { u8 r; u8 g; u8 b; }', + 'struct ExclamationBoxContents { u8 index; u8 unused; u8 firstByte; enum ModelExtendedId emodel; enum BehaviorId behaviorId; }' ] }] @@ -580,7 +581,7 @@ def def_struct(struct): return s def def_structs(structs): - s = '-- AUTOGENERATED FOR CODE EDITORS --\n' + s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\n\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 2faab968..a20b1634 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -1,4 +1,6 @@ --- AUTOGENERATED FOR CODE EDITORS -- +-- AUTOGENERATED FOR CODE EDITORS -- +--- @meta +--- @diagnostic disable math.randomseed(get_time()) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 36007e76..1fa36fd9 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -1,4 +1,6 @@ --- AUTOGENERATED FOR CODE EDITORS -- +-- AUTOGENERATED FOR CODE EDITORS -- +--- @meta +--- @diagnostic disable --- @param id integer --- @return ObjectWarpNode @@ -9023,6 +9025,11 @@ 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 c24e8c4d..3f77c6da 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -278,3 +278,15 @@ end 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) + -- ... +end \ No newline at end of file diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 38f4ef87..bd5c1b1f 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -1,4 +1,7 @@ --- AUTOGENERATED FOR CODE EDITORS -- +-- AUTOGENERATED FOR CODE EDITORS -- +--- @meta +--- @diagnostic disable + --- @class AnimInfo --- @field public animAccel integer @@ -1931,6 +1934,13 @@ --- @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 3b7dec61..7761d85b 100644 --- a/docs/lua/functions-5.md +++ b/docs/lua/functions-5.md @@ -2209,6 +2209,24 @@
+## [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 c1fc7d08..186d33d5 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1676,6 +1676,7 @@ - [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/structs.md b/docs/lua/structs.md index f4ea39ee..5fe94990 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -22,6 +22,7 @@ - [Cutscene](#Cutscene) - [CutsceneSplinePoint](#CutsceneSplinePoint) - [CutsceneVariable](#CutsceneVariable) +- [ExclamationBoxContents](#ExclamationBoxContents) - [FloorGeometry](#FloorGeometry) - [GlobalObjectAnimations](#GlobalObjectAnimations) - [GlobalObjectCollisionData](#GlobalObjectCollisionData) @@ -599,6 +600,20 @@
+## [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 4aac7922..03df7bd1 100644 --- a/src/game/behavior_actions.c +++ b/src/game/behavior_actions.c @@ -49,6 +49,10 @@ #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 { @@ -74,6 +78,7 @@ struct Struct8032F698 { s16 unk4; }; +/* Moved to smlua_obj_utils.h struct Struct802C0DF0 { u8 unk0; u8 unk1; @@ -81,6 +86,7 @@ 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 8a10a6af..109808f4 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 }, - { 99, 0, 0, 0, NULL } }; + { 255, 0, 0, 0, NULL } }; void bhv_rotating_exclamation_box_loop(void) { if (!o->parentObj || o->parentObj->oAction != 1) @@ -122,7 +122,7 @@ static s32 exclamation_replace_model(struct MarioState* m, s32 model) { } } -void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { +void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1, u8 size) { struct MarioState* marioState = nearest_mario_state_to_object(o); struct Object* player = marioState ? marioState->marioObj : NULL; struct Object *sp1C = NULL; @@ -131,7 +131,7 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { return; } - while (a0->unk0 != 99) { + for (u8 i = 0; i < size; i++) { if (a1 == a0->unk0) { s32 model = exclamation_replace_model(marioState, a0->model); @@ -152,6 +152,7 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { // stars cant be sent here to due jankiness in oBehParams if (a0->behavior != smlua_override_behavior(bhvSpawnedStar) && sp1C != 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); } @@ -166,7 +167,9 @@ void exclamation_box_spawn_contents(struct Struct802C0DF0 *a0, u8 a1) { } void exclamation_box_act_4(void) { - exclamation_box_spawn_contents(sExclamationBoxContents, o->oBehParams2ndByte); + 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); 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 81b36729..9181bd48 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -8,6 +8,7 @@ #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; @@ -321,6 +322,8 @@ 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 18809025..d401c974 100644 --- a/src/pc/lua/smlua_functions.c +++ b/src/pc/lua/smlua_functions.c @@ -14,6 +14,7 @@ #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); @@ -210,6 +211,98 @@ 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 // ////////////// @@ -747,4 +840,5 @@ 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 f31d657b..e75b7ab3 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -29647,6 +29647,21 @@ 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; } @@ -32167,6 +32182,7 @@ 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/utils/smlua_obj_utils.c b/src/pc/lua/utils/smlua_obj_utils.c index f87752a4..1bda952d 100644 --- a/src/pc/lua/utils/smlua_obj_utils.c +++ b/src/pc/lua/utils/smlua_obj_utils.c @@ -407,6 +407,27 @@ 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 48b0963f..5fae98bc 100644 --- a/src/pc/lua/utils/smlua_obj_utils.h +++ b/src/pc/lua/utils/smlua_obj_utils.h @@ -5,6 +5,14 @@ #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); @@ -57,4 +65,9 @@ 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