diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index f2d30851a..d981a171e 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -3276,7 +3276,7 @@ PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT = 10 PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE = -5 --- @type integer -PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY = 0x0000FFFF +PVP_ATTACK_KNOCKBACK_ACTION_ARG = 0x10000 --- @type integer INT_STATUS_ATTACK_MASK = 0x000000FF diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index c0680411a..2ba4a4366 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -97,11 +97,6 @@ gServerSettings = {} --- Struct containing the settings for Nametags gNametagsSettings = {} ---- @type Camera ---- Struct contaning camera fields ---- - This camera is the same as `gMarioStates[i].area.camera` or `gCurrentArea.camera` -gCamera = {} - ----------- -- hooks -- ----------- diff --git a/data/behavior_table.c b/data/behavior_table.c index 6fbdf122b..1312c363f 100644 --- a/data/behavior_table.c +++ b/data/behavior_table.c @@ -597,5 +597,11 @@ enum BehaviorId get_id_from_behavior_name(const char* name) { return i; } } + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior *hooked = &gHookedBehaviors[i]; + if (hooked->bhvName && !strcmp(name, hooked->bhvName)) { + return hooked->overrideId; + } + } return id_bhv_max_count; } diff --git a/data/dynos_bin_behavior.cpp b/data/dynos_bin_behavior.cpp index c6150025f..805a31ac8 100644 --- a/data/dynos_bin_behavior.cpp +++ b/data/dynos_bin_behavior.cpp @@ -2449,6 +2449,48 @@ static void ParseBehaviorScriptSymbol(GfxData *aGfxData, DataNode &aCommands) { + u8 bhvCommand = (*aBhv >> 24) & 0xFF; + for (const auto &commandToCheck : aCommands) { + if (bhvCommand == ((commandToCheck >> 24) & 0xFF)) { + return true; + } + } + return false; +} + +static bool DynOS_Bhv_Validate(GfxData *aGfxData, const DataNode *aNode) { + + // 1st command must be BEGIN + if (!DynOS_Bhv_CheckCommands(aNode->mData + 0, { BEGIN(0) })) { + PrintDataError(" ERROR: Validation failed for behavior %s: First command of the script must be BEGIN.", aNode->mName.begin()); + return false; + } + + // 2nd command must be ID + if (!DynOS_Bhv_CheckCommands(aNode->mData + 1, { ID(0) })) { + PrintDataError(" ERROR: Validation failed for behavior %s: Second command of the script must be ID.", aNode->mName.begin()); + return false; + } + + // Last command must be a terminating command + if (!DynOS_Bhv_CheckCommands(aNode->mData + aNode->mSize - 1, { + CALL(0), + RETURN(), + GOTO(0), + END_LOOP(), + BREAK(), + DEACTIVATE(), + CALL_EXT(0), + GOTO_EXT(0), + })) { + PrintDataError(" ERROR: Validation failed for behavior %s: Last command of the script must be one of:\n CALL, RETURN, GOTO, END_LOOP, BREAK, DEACTIVATE", aNode->mName.begin()); + return false; + } + + return true; +} + DataNode *DynOS_Bhv_Parse(GfxData *aGfxData, DataNode *aNode, bool aDisplayPercent) { if (aNode->mData) return aNode; @@ -2460,9 +2502,13 @@ DataNode *DynOS_Bhv_Parse(GfxData *aGfxData, DataNodemErrorCount == 0) { PrintNoNewLine("%3d%%\b\b\b\b", (s32) (_TokenIndex * 100) / aNode->mTokens.Count()); } } - if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); } aNode->mSize = (u32)(_Head - aNode->mData); aNode->mLoadIndex = aGfxData->mLoadIndex++; + + // Validate behavior script + DynOS_Bhv_Validate(aGfxData, aNode); + + if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); } return aNode; } @@ -2592,6 +2638,12 @@ static DataNode *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat } } + // Validate it + if (!DynOS_Bhv_Validate(aGfxData, _Node)) { + Delete(_Node); + return NULL; + } + // Add it if (aGfxData != NULL) { aGfxData->mBehaviorScripts.Add(_Node); diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 7632878e6..664556031 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -1459,7 +1459,7 @@ - ATTACK_FROM_BELOW - PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT - PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE -- PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY +- PVP_ATTACK_KNOCKBACK_ACTION_ARG - INT_STATUS_ATTACK_MASK - INT_STATUS_HOOT_GRABBED_BY_MARIO - INT_STATUS_MARIO_UNK1 diff --git a/include/behavior_table.h b/include/behavior_table.h index f4cf7146b..b3ab308f2 100644 --- a/include/behavior_table.h +++ b/include/behavior_table.h @@ -557,7 +557,7 @@ enum BehaviorId get_id_from_vanilla_behavior(const BehaviorScript* behavior); const BehaviorScript* get_behavior_from_id(enum BehaviorId id); /* |description|Gets a behavior name from a behavior ID (bhvMyGreatMODCustom004)|descriptionEnd| */ const char* get_behavior_name_from_id(enum BehaviorId id); -/* |description|gets a behavior ID from a behavior name|descriptionEnd| */ +/* |description|Gets a behavior ID from a behavior name|descriptionEnd| */ enum BehaviorId get_id_from_behavior_name(const char* name); #endif diff --git a/mods/sm74/actors/mad_toad_geo.bin b/mods/sm74/actors/mad_toad_geo.bin new file mode 100644 index 000000000..5ad7d0303 Binary files /dev/null and b/mods/sm74/actors/mad_toad_geo.bin differ diff --git a/mods/sm74/levels/level_bitfs_entry.lvl b/mods/sm74/levels/level_bitfs_entry.lvl index cdeb03e82..a07142d63 100644 Binary files a/mods/sm74/levels/level_bitfs_entry.lvl and b/mods/sm74/levels/level_bitfs_entry.lvl differ diff --git a/mods/sm74/levels/level_castle_courtyard_entry.lvl b/mods/sm74/levels/level_castle_courtyard_entry.lvl index c3d8685e2..1c4dd2c00 100644 Binary files a/mods/sm74/levels/level_castle_courtyard_entry.lvl and b/mods/sm74/levels/level_castle_courtyard_entry.lvl differ diff --git a/mods/sm74/levels/level_castle_inside_entry.lvl b/mods/sm74/levels/level_castle_inside_entry.lvl index 820240229..851bad051 100644 Binary files a/mods/sm74/levels/level_castle_inside_entry.lvl and b/mods/sm74/levels/level_castle_inside_entry.lvl differ diff --git a/mods/sm74/levels/level_ddd_entry.lvl b/mods/sm74/levels/level_ddd_entry.lvl index fe19d9a1e..ea13c048b 100644 Binary files a/mods/sm74/levels/level_ddd_entry.lvl and b/mods/sm74/levels/level_ddd_entry.lvl differ diff --git a/mods/star-road/helpers.lua b/mods/star-road/helpers.lua index acd6e4578..7c2dd67d7 100644 --- a/mods/star-road/helpers.lua +++ b/mods/star-road/helpers.lua @@ -52,6 +52,9 @@ function check_mario_attacking(obj, mario) if mario.action == ACT_WALL_KICK_AIR then return 2 end + if (mario.action & ACT_FLAG_CUSTOM_ACTION ~= 0) and (mario.action & ACT_FLAG_ATTACKING ~= 0) then + return 2 + end end end @@ -121,4 +124,4 @@ function object_drop_to_floor(obj) local floorHeight = find_floor_height(x, y + 200, z) obj.oPosY = floorHeight obj.oMoveFlags = (obj.oMoveFlags | OBJ_MOVE_ON_GROUND) -end \ No newline at end of file +end diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 8bfbdc3aa..bd6218775 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -987,6 +987,11 @@ static s32 bhv_cmd_call_native_ext(void) { } const char *funcStr = dynos_behavior_get_token(behavior, BHV_CMD_GET_U32(1)); + if (!funcStr) { + LOG_LUA("Could not retrieve function name from behavior command."); + gCurBhvCommand += 2; + return BHV_PROC_CONTINUE; + } gSmLuaConvertSuccess = true; LuaFunction funcRef = smlua_get_function_mod_variable(modIndex, funcStr); diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 08971c42d..15f6f9a9f 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -162,7 +162,7 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, closest_point_to_triangle(surf, src, cPos); // Exclude triangles where y isn't inside of it - if (cPos[1] < surf->lowerY || cPos[1] > surf->upperY) { continue; } + if (fabs(cPos[1] - y) > 1) { continue; } // Figure out normal f32 dX = src[0] - cPos[0]; diff --git a/src/game/interaction.c b/src/game/interaction.c index d81651099..4304a23ae 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -643,7 +643,9 @@ static u32 unused_determine_knockback_action(struct MarioState *m) { return bonkAction; } -u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) { +u32 determine_knockback_action(struct MarioState *m, RET bool *isPlayerAttack) { + *isPlayerAttack = false; + if (!m) { return 0; } if (m->interactObj == NULL) { return sForwardKnockbackActions[0][0]; @@ -739,6 +741,7 @@ u32 determine_knockback_action(struct MarioState *m, UNUSED s32 arg) { m->knockbackTimer = hasBeenPunched ? PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE : PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; #undef IF_REVAMPED_PVP m->faceAngle[1] = m->interactObj->oFaceAngleYaw + (sign == 1.0f ? 0 : 0x8000); + *isPlayerAttack = true; } return bonkAction; @@ -870,7 +873,10 @@ u32 take_damage_and_knock_back(struct MarioState *m, struct Object *o) { } update_mario_sound_and_camera(m); - return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue), damage); + + bool isPlayerAttack = false; + u32 knockbackAction = determine_knockback_action(m, &isPlayerAttack); + return drop_and_set_mario_action(m, knockbackAction, damage | (isPlayerAttack ? PVP_ATTACK_KNOCKBACK_ACTION_ARG : 0)); } return FALSE; @@ -1724,8 +1730,9 @@ u32 interact_snufit_bullet(struct MarioState *m, UNUSED u32 interactType, struct play_character_sound(m, CHAR_SOUND_ATTACKED); update_mario_sound_and_camera(m); - return drop_and_set_mario_action(m, determine_knockback_action(m, o->oDamageOrCoinValue), - o->oDamageOrCoinValue); + bool isPlayerAttack = false; + u32 knockbackAction = determine_knockback_action(m, &isPlayerAttack); + return drop_and_set_mario_action(m, knockbackAction, o->oDamageOrCoinValue | (isPlayerAttack ? PVP_ATTACK_KNOCKBACK_ACTION_ARG : 0)); } } diff --git a/src/game/interaction.h b/src/game/interaction.h index 7dfe20a74..d06e9a795 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -101,7 +101,7 @@ enum InteractionFlag { #define PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT 10 #define PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE -5 -#define PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY 0x0000FFFF +#define PVP_ATTACK_KNOCKBACK_ACTION_ARG 0x10000 #define INT_STATUS_ATTACK_MASK 0x000000FF diff --git a/src/game/mario.c b/src/game/mario.c index 2c1e6c56b..897bbc3fe 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1043,6 +1043,29 @@ static u32 set_mario_action_airborne(struct MarioState *m, u32 action, u32 actio case ACT_JUMP_KICK: m->vel[1] = 20.0f; break; + + // Set forward vel to a predefined value for non-player knockbacks + case ACT_BACKWARD_AIR_KB: + case ACT_HARD_BACKWARD_AIR_KB: + if (!(actionArg & PVP_ATTACK_KNOCKBACK_ACTION_ARG)) { + mario_set_forward_vel(m, -16.0f); + } + break; + + case ACT_FORWARD_AIR_KB: + case ACT_HARD_FORWARD_AIR_KB: + if (!(actionArg & PVP_ATTACK_KNOCKBACK_ACTION_ARG)) { + mario_set_forward_vel(m, 16.0f); + } + break; + + case ACT_THROWN_BACKWARD: + case ACT_THROWN_FORWARD: + case ACT_SOFT_BONK: + if (!(actionArg & PVP_ATTACK_KNOCKBACK_ACTION_ARG)) { + mario_set_forward_vel(m, m->forwardVel); // needed to update velocities + } + break; } m->peakHeight = m->pos[1]; @@ -2221,6 +2244,7 @@ void init_single_mario(struct MarioState* m) { m->heldObj = NULL; m->heldByObj = NULL; + m->interactObj = NULL; m->riddenObj = NULL; m->usedObj = NULL; m->bubbleObj = NULL; diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 5bf71f395..00b338447 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -57,7 +57,7 @@ depending on whether Mario's forward velocity is high enough to be considered a |descriptionEnd| */ void play_knockback_sound(struct MarioState *m) { if (!m) { return; } - if (m->actionArg == 0 && (m->forwardVel <= -28.0f || m->forwardVel >= 28.0f)) { + if ((m->actionArg & ~PVP_ATTACK_KNOCKBACK_ACTION_ARG) == 0 && (m->forwardVel <= -28.0f || m->forwardVel >= 28.0f)) { play_character_sound_if_no_flag(m, CHAR_SOUND_DOH, MARIO_MARIO_SOUND_PLAYED); } else { play_character_sound_if_no_flag(m, CHAR_SOUND_UH, MARIO_MARIO_SOUND_PLAYED); @@ -1236,13 +1236,8 @@ u32 common_air_knockback_step(struct MarioState *m, u32 landAction, u32 hardFall if (!m) { return 0; } u32 stepResult; - if (m->knockbackTimer == 0) { - if (m->interactObj == NULL || !(m->interactObj->oInteractType & INTERACT_PLAYER)) { - mario_set_forward_vel(m, speed); - } - } else if (m->knockbackTimer < 0) { - // do nothing - } else { + // Refresh knockbackTimer + if (m->knockbackTimer > 0) { m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; } @@ -1356,7 +1351,7 @@ s32 act_hard_forward_air_kb(struct MarioState *m) { s32 act_thrown_backward(struct MarioState *m) { if (!m) { return 0; } u32 landAction; - if (m->actionArg != 0) { + if ((m->actionArg & ~PVP_ATTACK_KNOCKBACK_ACTION_ARG) != 0) { landAction = ACT_HARD_BACKWARD_GROUND_KB; } else { landAction = ACT_BACKWARD_GROUND_KB; @@ -1375,7 +1370,7 @@ s32 act_thrown_forward(struct MarioState *m) { s16 pitch; u32 landAction; - if (m->actionArg != 0) { + if ((m->actionArg & ~PVP_ATTACK_KNOCKBACK_ACTION_ARG) != 0) { landAction = ACT_HARD_FORWARD_GROUND_KB; } else { landAction = ACT_FORWARD_GROUND_KB; diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 6a21d45d5..c502e5f31 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -1775,12 +1775,13 @@ Handles knockback on the ground (getting hit while on the ground) with shared lo s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2, s32 arg3, s32 arg4) { if (!m) { return 0; } s32 animFrame; + s32 damage = arg4 & ~PVP_ATTACK_KNOCKBACK_ACTION_ARG; if (arg3) { play_mario_heavy_landing_sound_once(m, SOUND_ACTION_TERRAIN_BODY_HIT_GROUND); } - if (arg4 > 0) { + if (damage > 0) { play_character_sound_if_no_flag(m, CHAR_SOUND_ATTACKED, MARIO_MARIO_SOUND_PLAYED); } else { #ifdef VERSION_JP @@ -1790,18 +1791,18 @@ s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2 #endif } - if (m->knockbackTimer == 0) { - if (m->interactObj == NULL || !(m->interactObj->oInteractType & INTERACT_PLAYER)) { - if (m->forwardVel > 32.0f) { - m->forwardVel = 32.0f; - } - if (m->forwardVel < -32.0f) { - m->forwardVel = -32.0f; - } + // Cap speed if it's not a PVP attack + if (!(arg4 & PVP_ATTACK_KNOCKBACK_ACTION_ARG)) { + if (m->forwardVel > 32.0f) { + m->forwardVel = 32.0f; } - } else if (m->knockbackTimer < 0) { - // do nothing - } else { + if (m->forwardVel < -32.0f) { + m->forwardVel = -32.0f; + } + } + + // Refresh knockbackTimer + if (m->knockbackTimer > 0) { m->knockbackTimer = PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT; } @@ -1824,7 +1825,7 @@ s32 common_ground_knockback_action(struct MarioState *m, s32 animation, s32 arg2 if (m->health < 0x100) { set_mario_action(m, ACT_STANDING_DEATH, 0); } else { - if (arg4 > 0) { + if (damage > 0) { m->invincTimer = 30; } set_mario_action(m, ACT_IDLE, 0); diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 4c13b7cfa..7cb509211 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -769,13 +769,13 @@ static struct PlayerColor geo_mario_get_player_color(const struct PlayerPalette for (s32 part = 0; part != PLAYER_PART_MAX; ++part) { color.parts[part] = (Lights1) gdSPDefLights1( // Shadow - palette->parts[part][0] * bodyState->shadeR / 255.0f, - palette->parts[part][1] * bodyState->shadeG / 255.0f, - palette->parts[part][2] * bodyState->shadeB / 255.0f, + min(palette->parts[part][0] * bodyState->shadeR / 255.0f, 255), + min(palette->parts[part][1] * bodyState->shadeG / 255.0f, 255), + min(palette->parts[part][2] * bodyState->shadeB / 255.0f, 255), // Light - palette->parts[part][0] * bodyState->lightR / 255.0f, - palette->parts[part][1] * bodyState->lightG / 255.0f, - palette->parts[part][2] * bodyState->lightB / 255.0f, + min(palette->parts[part][0] * bodyState->lightR / 255.0f, 255), + min(palette->parts[part][1] * bodyState->lightG / 255.0f, 255), + min(palette->parts[part][2] * bodyState->lightB / 255.0f, 255), 0x28 + bodyState->lightingDirX * 127.0f, 0x28 + bodyState->lightingDirY * 127.0f, 0x28 + bodyState->lightingDirZ * 127.0f ); } diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index d0e4c65ca..9972d5535 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -331,6 +331,9 @@ struct Object *allocate_object(struct ObjectNode *objList) { vec3s_zero(obj->header.gfx.angle); obj->header.gfx.throwMatrix = NULL; obj->header.gfx.inited = false; + obj->header.gfx.disableAutomaticShadowPos = false; + obj->header.gfx.shadowInvisible = false; + obj->header.gfx.skipInViewCheck = false; obj->coopFlags = 0; obj->hookRender = 0; diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index a55aae378..129a8f876 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -1653,7 +1653,7 @@ char gSmluaConstants[] = "" "ATTACK_FROM_BELOW=6\n" "PVP_ATTACK_KNOCKBACK_TIMER_DEFAULT=10\n" "PVP_ATTACK_KNOCKBACK_TIMER_OVERRIDE=-5\n" -"PVP_ATTACK_OVERRIDE_VANILLA_INVINCIBILITY=0x0000FFFF\n" +"PVP_ATTACK_KNOCKBACK_ACTION_ARG=0x10000\n" "INT_STATUS_ATTACK_MASK=0x000000FF\n" "INT_STATUS_HOOT_GRABBED_BY_MARIO=(1 << 0)\n" "INT_STATUS_MARIO_UNK1=(1 << 1)\n" diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index d487aa2ac..9bfc6dceb 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -398,30 +398,13 @@ u32 smlua_get_action_interaction_type(struct MarioState* m) { // hooked behaviors // ////////////////////// -struct LuaHookedBehavior { - u32 behaviorId; - u32 overrideId; - u32 originalId; - BehaviorScript *behavior; - const BehaviorScript* originalBehavior; - const char* bhvName; - int initReference; - int loopReference; - bool replace; - bool luaBehavior; - struct Mod* mod; - struct ModFile* modFile; -}; - -#define MAX_HOOKED_BEHAVIORS 1024 - -static struct LuaHookedBehavior sHookedBehaviors[MAX_HOOKED_BEHAVIORS] = { 0 }; -static int sHookedBehaviorsCount = 0; +struct LuaHookedBehavior gHookedBehaviors[MAX_HOOKED_BEHAVIORS] = { 0 }; +int gHookedBehaviorsCount = 0; enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior) { enum BehaviorId id = get_id_from_behavior(behavior); - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &gHookedBehaviors[i]; if (hooked->behavior == behavior) { id = hooked->overrideId; } @@ -443,8 +426,8 @@ const BehaviorScript* smlua_get_hooked_behavior_from_id(enum BehaviorId id, bool lua_State *L = gLuaState; if (L == NULL) { return NULL; } - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &gHookedBehaviors[i]; if (hooked->behaviorId != id && hooked->overrideId != id) { continue; } if (returnOriginal && !hooked->replace) { return hooked->originalBehavior; } return hooked->behavior; @@ -457,8 +440,8 @@ bool smlua_is_behavior_hooked(const BehaviorScript *behavior) { if (L == NULL) { return false; } enum BehaviorId id = get_id_from_behavior(behavior); - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior *hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior *hooked = &gHookedBehaviors[i]; if (hooked->behaviorId != id && hooked->overrideId != id) { continue; } return hooked->luaBehavior; } @@ -467,8 +450,8 @@ bool smlua_is_behavior_hooked(const BehaviorScript *behavior) { } const char* smlua_get_name_from_hooked_behavior_id(enum BehaviorId id) { - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior *hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior *hooked = &gHookedBehaviors[i]; if (hooked->behaviorId != id && hooked->overrideId != id) { continue; } return hooked->bhvName; } @@ -476,7 +459,7 @@ const char* smlua_get_name_from_hooked_behavior_id(enum BehaviorId id) { } int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) { - if (sHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { + if (gHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { LOG_ERROR("Hooked behaviors exceeded maximum references!"); return 0; } @@ -490,8 +473,8 @@ int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) { u8 newBehavior = originalBehaviorId >= id_bhv_max_count; - struct LuaHookedBehavior *hooked = &sHookedBehaviors[sHookedBehaviorsCount]; - u16 customBehaviorId = (sHookedBehaviorsCount & 0xFFFF) | LUA_BEHAVIOR_FLAG; + struct LuaHookedBehavior *hooked = &gHookedBehaviors[gHookedBehaviorsCount]; + u16 customBehaviorId = (gHookedBehaviorsCount & 0xFFFF) | LUA_BEHAVIOR_FLAG; hooked->behavior = bhvScript; hooked->behavior[1] = (BehaviorScript)BC_B0H(0x39, customBehaviorId); // This is ID(customBehaviorId) hooked->behaviorId = customBehaviorId; @@ -506,7 +489,7 @@ int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) { hooked->mod = gLuaActiveMod; hooked->modFile = gLuaActiveModFile; - sHookedBehaviorsCount++; + gHookedBehaviorsCount++; // We want to push the behavior into the global LUA state. So mods can access it. // It's also used for some things that would normally access a LUA behavior instead. @@ -531,7 +514,7 @@ int smlua_hook_behavior(lua_State* L) { int paramCount = lua_gettop(L); - if (sHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { + if (gHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { LOG_LUA_LINE("Hooked behaviors exceeded maximum references!"); return 0; } @@ -634,8 +617,8 @@ int smlua_hook_behavior(lua_State* L) { bhvName = sGenericBhvName; } - struct LuaHookedBehavior* hooked = &sHookedBehaviors[sHookedBehaviorsCount]; - u16 customBehaviorId = (sHookedBehaviorsCount & 0xFFFF) | LUA_BEHAVIOR_FLAG; + struct LuaHookedBehavior* hooked = &gHookedBehaviors[gHookedBehaviorsCount]; + u16 customBehaviorId = (gHookedBehaviorsCount & 0xFFFF) | LUA_BEHAVIOR_FLAG; hooked->behavior = calloc(4, sizeof(BehaviorScript)); hooked->behavior[0] = (BehaviorScript)BC_BB(0x00, objectList); // This is BEGIN(objectList) hooked->behavior[1] = (BehaviorScript)BC_B0H(0x39, customBehaviorId); // This is ID(customBehaviorId) @@ -653,7 +636,7 @@ int smlua_hook_behavior(lua_State* L) { hooked->mod = gLuaActiveMod; hooked->modFile = gLuaActiveModFile; - sHookedBehaviorsCount++; + gHookedBehaviorsCount++; // We want to push the behavior into the global LUA state. So mods can access it. // It's also used for some things that would normally access a LUA behavior instead. @@ -670,8 +653,8 @@ int smlua_hook_behavior(lua_State* L) { bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* object, bool before) { lua_State* L = gLuaState; if (L == NULL) { return false; } - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &gHookedBehaviors[i]; // find behavior if (object->behavior != hooked->behavior) { @@ -1518,8 +1501,8 @@ void smlua_hook_replace_function_references(lua_State* L, int oldReference, int smlua_hook_replace_function_reference(L, &hooked->reference, oldReference, newReference); } - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &gHookedBehaviors[i]; smlua_hook_replace_function_reference(L, &hooked->initReference, oldReference, newReference); smlua_hook_replace_function_reference(L, &hooked->loopReference, oldReference, newReference); } @@ -1574,8 +1557,8 @@ void smlua_clear_hooks(void) { } gHookedModMenuElementsCount = 0; - for (int i = 0; i < sHookedBehaviorsCount; i++) { - struct LuaHookedBehavior* hooked = &sHookedBehaviors[i]; + for (int i = 0; i < gHookedBehaviorsCount; i++) { + struct LuaHookedBehavior* hooked = &gHookedBehaviors[i]; // If this is NULL. We can't do anything with it. if (hooked->behavior != NULL) { @@ -1601,7 +1584,7 @@ void smlua_clear_hooks(void) { hooked->mod = NULL; hooked->modFile = NULL; } - sHookedBehaviorsCount = 0; + gHookedBehaviorsCount = 0; memset(gLuaMarioActionIndex, 0, sizeof(gLuaMarioActionIndex)); } diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index edfcc975f..a857bbad3 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -127,6 +127,26 @@ extern u32 gLuaMarioActionIndex[]; extern struct LuaHookedModMenuElement gHookedModMenuElements[]; extern int gHookedModMenuElementsCount; +#define MAX_HOOKED_BEHAVIORS 1024 + +struct LuaHookedBehavior { + u32 behaviorId; + u32 overrideId; + u32 originalId; + BehaviorScript *behavior; + const BehaviorScript* originalBehavior; + const char* bhvName; + int initReference; + int loopReference; + bool replace; + bool luaBehavior; + struct Mod* mod; + struct ModFile* modFile; +}; + +extern int gHookedBehaviorsCount; +extern struct LuaHookedBehavior gHookedBehaviors[MAX_HOOKED_BEHAVIORS]; + #define OUTPUT #define SMLUA_EVENT_HOOK(hookEventType, hookReturn, ...) bool smlua_call_event_hooks_##hookEventType(__VA_ARGS__); #include "smlua_hook_events.inl"