From d87dd73db1741da58aab75b7438f14887d434ab9 Mon Sep 17 00:00:00 2001 From: TheGag96 Date: Sun, 7 Aug 2022 17:25:00 -0500 Subject: [PATCH] Fix issues Extended Moveset mod (+ extras) (#146) * Allow Lua action hooks to specify custom functions for more behavior ...like gravity, and update all current mods to match. Spin jump and wall slide from the Extended Moveset mod now have gravity code basically matching the original mod. Currently, any place you'd want to use one of these new action hooks still requires an O(n) check through all action hook per call. This should probably be changed. * Fix some remaining issues with Extended Moveset Lua port - Remove divergent spin jump code - Remove divergent roll code - Remap roll button to Y - Reimplement dive slide to make dive hop work like the original - Allow spin from double jump, backflip, side flip * Fix more issues with Extended Moveset Lua port - Reimplement all users of update_walking_speed to incorporate the Tight Controls edits and modified speed caps - Fix instances of angle arithmetic to wrap properly across the mod * Don't chop off group bits of custom action flags; assign missing groups in mods This fixes the Extended Moveset's underwater actions. Chopping off those bits was making the game consider the underwater actions to be a part of the Stationary group, which caused `check_common_stationary_cancels`, which upwarps Mario to the surface. * Tweak roll sliding angle tendency Rolling will now gradually (but fairly quckly) try to tend Mario's facing angle down the slope. This is cleaner than my old method that tries to flip Mario's angle (wrongly) when he begins moving downward, having that logic coexist with the logic for normal sliding actions that can also tend Mario to face backward down the slope. Just looks ugly now by comparison. * Disallow spin jump on slides in Extended Moveset port This matches the original mod * Extended Moveset: Crazy Box Bounce check * Extended Moveset: Fix hugging the wall when spin jumping after wall kick * Extended Moveset: Fix ledge drop snapping up to ground Just reimplement `act_air_hit_wall` ourselves. * Extended Moveset: Add Kaze's walking speed fix * smlua_hooks.c: Restore option to use old API for hook_mario_action The intent is to allow mods outside of this repo to continue working. Co-authored-by: djoslin0 --- autogen/lua_definitions/manual.lua | 4 +- docs/lua/constants.md | 8 + docs/lua/hooks.md | 22 +- mods/character-movesets.lua | 28 +- mods/extended-moveset.lua | 557 ++++++++++++++++++++++----- mods/shell-rush/actions.lua | 6 +- src/game/mario_actions_airborne.c | 2 +- src/game/mario_actions_automatic.c | 2 +- src/game/mario_actions_cutscene.c | 2 +- src/game/mario_actions_moving.c | 2 +- src/game/mario_actions_object.c | 2 +- src/game/mario_actions_stationary.c | 2 +- src/game/mario_actions_submerged.c | 2 +- src/game/mario_step.c | 4 + src/pc/lua/smlua_constants_autogen.c | 6 +- src/pc/lua/smlua_hooks.c | 58 ++- src/pc/lua/smlua_hooks.h | 14 +- src/pc/lua/utils/smlua_misc_utils.c | 2 +- 18 files changed, 574 insertions(+), 149 deletions(-) diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index d5e4e35ac..9effb01fb 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -71,9 +71,9 @@ function hook_event(hookEventType, func) end --- @param actionId integer ---- @param func fun(m:MarioState):integer +--- @param funcOrFuncTable fun(m:MarioState):integer | table(fun(m:MarioState):integer) --- @param interactionType InteractionFlag -function hook_mario_action(actionId, func, interactionType) +function hook_mario_action(actionId, funcOrFuncTable, interactionType) -- ... end diff --git a/docs/lua/constants.md b/docs/lua/constants.md index a5188c0bc..760541f8c 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -45,6 +45,7 @@ - [enum SeqId](#enum-SeqId) - [sm64.h](#sm64h) - [smlua_hooks.h](#smlua_hooksh) + - [enum LuaActionHookType](#enum-LuaActionHookType) - [enum LuaHookedEventType](#enum-LuaHookedEventType) - [smlua_misc_utils.h](#smlua_misc_utilsh) - [enum HudDisplayFlags](#enum-HudDisplayFlags) @@ -2766,6 +2767,13 @@ ## [smlua_hooks.h](#smlua_hooks.h) +### [enum LuaActionHookType](#LuaActionHookType) +| Identifier | Value | +| :--------- | :---- | +| ACTION_HOOK_EVERY_FRAME | 0 | +| ACTION_HOOK_GRAVITY | 1 | +| ACTION_HOOK_MAX | 2 | + ### [enum LuaHookedEventType](#LuaHookedEventType) | Identifier | Value | | :--------- | :---- | diff --git a/docs/lua/hooks.md b/docs/lua/hooks.md index 369dbbcf8..dd39d3999 100644 --- a/docs/lua/hooks.md +++ b/docs/lua/hooks.md @@ -141,9 +141,16 @@ hook_event(HOOK_MARIO_UPDATE, mario_update) | Field | Type | | ----- | ---- | | action_id | `integer` | -| func | `Lua Function` ([MarioState](structs.md#MarioState) m) | +| func | Table with entries for [Action Hook Types](#action-hook-types) of `Lua Function` ([MarioState](structs.md#MarioState) m) | | interaction_type | [enum InteractionFlag](constants.md#enum-InteractionFlag) | +#### [Action Hook Types](#action-hook-types) + +| Type | Description | Returns | +| :--- | :---------- | :------ | +| every_frame | Main action code, called once per frame | `true` if action cancelled, else `false` | +| gravity | Called inside `apply_gravity` when in action | Unused | + ### Lua Example ```lua @@ -183,12 +190,17 @@ function act_wall_slide(m) return set_mario_action(m, ACT_FREEFALL, 0) end - -- gravity - m.vel.y = m.vel.y + 2 - return 0 end +function act_wall_slide_gravity(m) + m.vel.y = m.vel.y - 2 + + if m.vel.y < -15 then + m.vel.y = -15 + end +end + function mario_on_set_action(m) -- wall slide if m.action == ACT_SOFT_BONK then @@ -198,7 +210,7 @@ function mario_on_set_action(m) end hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action) -hook_mario_action(ACT_WALL_SLIDE, act_wall_slide) +hook_mario_action(ACT_WALL_SLIDE, { every_frame = act_wall_slide, gravity = act_wall_slide_gravity } ) ``` [:arrow_up_small:](#) diff --git a/mods/character-movesets.lua b/mods/character-movesets.lua index 515e2b9dc..b7d1ea207 100644 --- a/mods/character-movesets.lua +++ b/mods/character-movesets.lua @@ -36,8 +36,8 @@ end -- luigi -- ----------- -ACT_SPIN_POUND_LAND = allocate_mario_action(ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING) -ACT_SPIN_POUND = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ATTACKING) +ACT_SPIN_POUND_LAND = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING) +ACT_SPIN_POUND = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING) function act_spin_pound(m) local e = gStateExtras[m.playerIndex] @@ -360,7 +360,7 @@ gEventTable[CT_TOAD] = { -- waluigi -- ------------- -ACT_WALL_SLIDE = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_WALL_SLIDE = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) function act_wall_slide(m) if (m.input & INPUT_A_PRESSED) ~= 0 then @@ -482,10 +482,10 @@ gEventTable[CT_WALUIGI] = { -- wario -- ----------- -ACT_WARIO_DASH = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_ATTACKING) -ACT_WARIO_AIR_DASH = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ATTACKING) -ACT_CORKSCREW_CONK = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) -ACT_WARIO_SPINNING_OBJ = allocate_mario_action(ACT_FLAG_STATIONARY) +ACT_WARIO_DASH = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_MOVING | ACT_FLAG_ATTACKING) +ACT_WARIO_AIR_DASH = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING) +ACT_CORKSCREW_CONK = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_WARIO_SPINNING_OBJ = allocate_mario_action(ACT_GROUP_OBJECT | ACT_FLAG_STATIONARY) function act_corkscrew_conk(m) local e = gStateExtras[m.playerIndex] @@ -1009,10 +1009,10 @@ hook_event(HOOK_MARIO_UPDATE, mario_update) hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action) hook_event(HOOK_BEFORE_PHYS_STEP, mario_before_phys_step) -hook_mario_action(ACT_WALL_SLIDE, act_wall_slide) -hook_mario_action(ACT_SPIN_POUND, act_spin_pound, INT_GROUND_POUND_OR_TWIRL) -hook_mario_action(ACT_SPIN_POUND_LAND, act_spin_pound_land, INT_GROUND_POUND_OR_TWIRL) -hook_mario_action(ACT_WARIO_DASH, act_wario_dash, INT_PUNCH) -hook_mario_action(ACT_WARIO_AIR_DASH, act_wario_air_dash, INT_PUNCH) -hook_mario_action(ACT_CORKSCREW_CONK, act_corkscrew_conk, INT_FAST_ATTACK_OR_SHELL) -hook_mario_action(ACT_WARIO_SPINNING_OBJ, act_wario_spinning_obj) +hook_mario_action(ACT_WALL_SLIDE, { every_frame = act_wall_slide }) +hook_mario_action(ACT_SPIN_POUND, { every_frame = act_spin_pound }, INT_GROUND_POUND_OR_TWIRL) +hook_mario_action(ACT_SPIN_POUND_LAND, { every_frame = act_spin_pound_land }, INT_GROUND_POUND_OR_TWIRL) +hook_mario_action(ACT_WARIO_DASH, { every_frame = act_wario_dash }, INT_PUNCH) +hook_mario_action(ACT_WARIO_AIR_DASH, { every_frame = act_wario_air_dash }, INT_PUNCH) +hook_mario_action(ACT_CORKSCREW_CONK, { every_frame = act_corkscrew_conk }, INT_FAST_ATTACK_OR_SHELL) +hook_mario_action(ACT_WARIO_SPINNING_OBJ, { every_frame = act_wario_spinning_obj }) diff --git a/mods/extended-moveset.lua b/mods/extended-moveset.lua index b3b5f02ec..0cbd6ec41 100644 --- a/mods/extended-moveset.lua +++ b/mods/extended-moveset.lua @@ -6,18 +6,18 @@ -- initialize actions -- ------------------------ -ACT_SPIN_POUND_LAND = allocate_mario_action(ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING) -ACT_ROLL = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE) -ACT_GROUND_POUND_JUMP = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) -ACT_SPIN_JUMP = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) -ACT_SPIN_POUND = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ATTACKING) -ACT_LEDGE_PARKOUR = allocate_mario_action(ACT_FLAG_AIR) -ACT_ROLL_AIR = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) -ACT_WALL_SLIDE = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) -ACT_WATER_GROUND_POUND = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT | ACT_FLAG_ATTACKING) -ACT_WATER_GROUND_POUND_LAND = allocate_mario_action(ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) -ACT_WATER_GROUND_POUND_STROKE = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) -ACT_WATER_GROUND_POUND_JUMP = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) +ACT_SPIN_POUND_LAND = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING) +ACT_ROLL = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE) +ACT_GROUND_POUND_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_SPIN_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_SPIN_POUND = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING) +ACT_LEDGE_PARKOUR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR) +ACT_ROLL_AIR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_WALL_SLIDE = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) +ACT_WATER_GROUND_POUND = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT | ACT_FLAG_ATTACKING) +ACT_WATER_GROUND_POUND_LAND = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) +ACT_WATER_GROUND_POUND_STROKE = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) +ACT_WATER_GROUND_POUND_JUMP = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) ----------------------------- -- initialize extra fields -- @@ -57,6 +57,10 @@ for i=0,(MAX_PLAYERS-1) do e.savedWallSlide = false end +function limit_angle(a) + return (a + 0x8000) % 0x10000 - 0x8000 +end + ---------- -- roll -- ---------- @@ -74,27 +78,19 @@ function update_roll_sliding_angle(m, accel, lossFactor) m.slideYaw = atan2s(m.slideVelZ, m.slideVelX) - local facingDYaw = m.faceAngle.y - m.slideYaw + local facingDYaw = limit_angle(m.faceAngle.y - m.slideYaw) local newFacingDYaw = facingDYaw - if newFacingDYaw > 0 and newFacingDYaw <= 0x4000 then - newFacingDYaw = newFacingDYaw - 0x200 + if newFacingDYaw > 0 and newFacingDYaw <= 0x8000 then + newFacingDYaw = newFacingDYaw - 0x800 if newFacingDYaw < 0 then newFacingDYaw = 0 end - elseif newFacingDYaw >= -0x4000 and newFacingDYaw < 0 then - newFacingDYaw = newFacingDYaw + 0x200 + elseif newFacingDYaw >= -0x8000 and newFacingDYaw < 0 then + newFacingDYaw = newFacingDYaw + 0x800 if newFacingDYaw > 0 then newFacingDYaw = 0 end - - elseif newFacingDYaw > 0x4000 and newFacingDYaw < 0x8000 then - newFacingDYaw = newFacingDYaw + 0x200 - if newFacingDYaw > 0x8000 then newFacingDYaw = 0x8000 end - - elseif newFacingDYaw > -0x8000 and newFacingDYaw < -0x4000 then - newFacingDYaw = newFacingDYaw - 0x200 - if newFacingDYaw < -0x8000 then newFacingDYaw = -0x8000 end end - m.faceAngle.y = m.slideYaw + newFacingDYaw + m.faceAngle.y = limit_angle(m.slideYaw + newFacingDYaw) m.vel.x = m.slideVelX m.vel.y = 0.0 @@ -109,15 +105,6 @@ function update_roll_sliding_angle(m, accel, lossFactor) m.slideVelX = m.slideVelX * 100.0 / m.forwardVel m.slideVelZ = m.slideVelZ * 100.0 / m.forwardVel end - - if newFacingDYaw < -0x4000 or newFacingDYaw > 0x4000 then - m.forwardVel = m.forwardVel * -1.0 - m.faceAngle.y = m.faceAngle.y + 0x4000 - end - - -- HACK: instead of approaching slideYaw, just set faceAngle to it - -- this is different than the original Extended Movement... just couldn't figure out the bug - m.faceAngle.y = m.slideYaw end function update_roll_sliding(m, stopSpeed) @@ -196,7 +183,7 @@ function act_roll(m) return set_jumping_action(m, ACT_LONG_JUMP, 0) end - if (m.controller.buttonPressed & U_JPAD) ~= 0 and m.actionTimer > 0 then + if (m.controller.buttonPressed & X_BUTTON) ~= 0 and m.actionTimer > 0 then m.vel.y = 19.0 play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) @@ -305,7 +292,7 @@ function update_roll(m) end if m.action == ACT_CROUCHING then - if (m.controller.buttonPressed & U_JPAD) ~= 0 then + if (m.controller.buttonPressed & X_BUTTON) ~= 0 then m.vel.y = 19.0 mario_set_forward_vel(m, 32.0) play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) @@ -317,7 +304,7 @@ function update_roll(m) end if m.action == ACT_CROUCH_SLIDE then - if (m.controller.buttonPressed & U_JPAD) ~= 0 then + if (m.controller.buttonPressed & X_BUTTON) ~= 0 then m.vel.y = 19.0 mario_set_forward_vel(m, math.max(32, m.forwardVel)) play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) @@ -329,7 +316,7 @@ function update_roll(m) end if m.action == ACT_GROUND_POUND_LAND then - if (m.controller.buttonPressed & U_JPAD) ~= 0 then + if (m.controller.buttonPressed & X_BUTTON) ~= 0 then mario_set_forward_vel(m, 60) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) @@ -358,7 +345,7 @@ function mario_update_spin_input(m) local signedOverflow = 0 if rawAngle < e.stickLastAngle then - if (e.stickLastAngle - rawAngle) > 0x8000 then + if e.stickLastAngle - rawAngle > 0x8000 then signedOverflow = 1 end if signedOverflow ~= 0 then @@ -367,7 +354,7 @@ function mario_update_spin_input(m) newDirection = -1 end elseif rawAngle > e.stickLastAngle then - if (rawAngle - e.stickLastAngle) > 0x8000 then + if rawAngle - e.stickLastAngle > 0x8000 then signedOverflow = 1 end if signedOverflow ~= 0 then @@ -455,7 +442,7 @@ function act_spin_jump(m) if (m.input & INPUT_NONZERO_ANALOG) ~= 0 then m.faceAngle.y = m.intendedYaw else - m.faceAngle.y = e.rotAngle + m.faceAngle.y = limit_angle(e.rotAngle) end return set_mario_action(m, ACT_SPIN_POUND, m.actionState) @@ -466,21 +453,17 @@ function act_spin_jump(m) common_air_action_step(m, ACT_DOUBLE_JUMP_LAND, MARIO_ANIM_TWIRL, AIR_STEP_CHECK_HANG) - if (e.savedWallSlide == false) or (m.pos.y <= e.savedWallSlideHeight) then - -- set facing direction - -- not part of original Extended Moveset - local yawDiff = m.faceAngle.y - m.intendedYaw - e.rotAngle = e.rotAngle + yawDiff - m.faceAngle.y = m.intendedYaw - end - e.rotAngle = e.rotAngle + 0x2867 if (e.rotAngle > 0x10000) then e.rotAngle = e.rotAngle - 0x10000 end if (e.rotAngle < -0x10000) then e.rotAngle = e.rotAngle + 0x10000 end - m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + (e.rotAngle * spinDirFactor) + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + (e.rotAngle * spinDirFactor)) - -- gravity - m.vel.y = m.vel.y + 2 + m.actionTimer = m.actionTimer + 1 + + return false +end + +function act_spin_jump_gravity(m) if (m.flags & MARIO_WING_CAP) ~= 0 and m.vel.y < 0.0 and (m.input & INPUT_A_DOWN) ~= 0 then m.marioBodyState.wingFlutter = 1 m.vel.y = m.vel.y - 0.7 @@ -494,17 +477,15 @@ function act_spin_jump(m) if m.vel.y > 0 then m.vel.y = m.vel.y - 4 else - m.vel.y = m.vel.y + 1.4 + m.vel.y = m.vel.y - 1.4 end if m.vel.y < -75.0 then - m.vel.y = -75.5 + m.vel.y = -75.0 end end - m.actionTimer = m.actionTimer + 1 - - return false + return 0 end function act_spin_pound(m) @@ -552,13 +533,13 @@ function act_spin_pound(m) -- set facing direction -- not part of original Extended Moveset local yawDiff = m.faceAngle.y - m.intendedYaw - e.rotAngle = e.rotAngle + yawDiff + e.rotAngle = limit_angle(e.rotAngle + yawDiff) m.faceAngle.y = m.intendedYaw e.rotAngle = e.rotAngle + 0x3053 if e.rotAngle > 0x10000 then e.rotAngle = e.rotAngle - 0x10000 end if e.rotAngle < -0x10000 then e.rotAngle = e.rotAngle + 0x10000 end - m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + e.rotAngle * spinDirFactor + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + e.rotAngle * spinDirFactor) m.actionTimer = m.actionTimer + 1 @@ -586,7 +567,7 @@ function act_spin_pound_land(m) return set_jumping_action(m, ACT_GROUND_POUND_JUMP, 0) end - if (m.controller.buttonPressed & U_JPAD) ~= 0 then + if (m.controller.buttonPressed & X_BUTTON) ~= 0 then mario_set_forward_vel(m, 60) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) @@ -623,7 +604,7 @@ function act_wall_slide(m) if (m.input & INPUT_A_PRESSED) ~= 0 then m.vel.y = 52.0 - -- m.faceAngle.y = m.faceAngle.y + 0x8000 + -- m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) return set_mario_action(m, ACT_WALL_KICK_AIR, 0) end @@ -648,12 +629,50 @@ function act_wall_slide(m) return set_mario_action(m, ACT_FREEFALL, 0) end - -- gravity - m.vel.y = m.vel.y + 2 - return 0 end +function act_wall_slide_gravity(m) + m.vel.y = m.vel.y - 2 + + if m.vel.y < -15 then + m.vel.y = -15 + end +end + +function act_air_hit_wall(m) + if m.heldObj ~= 0 then + mario_drop_held_object(m) + end + + m.actionTimer = m.actionTimer + 1 + if m.actionTimer <= 1 and (m.input & INPUT_A_PRESSED) ~= 0 then + m.vel.y = 52.0 + m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) + return set_mario_action(m, ACT_WALL_KICK_AIR, 0) + elseif m.forwardVel >= 38.0 then + m.wallKickTimer = 5 + if m.vel.y > 0.0 then + m.vel.y = 0.0 + end + + m.particleFlags = m.particleFlags | PARTICLE_VERTICAL_STAR + return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) + else + m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) + return set_mario_action(m, ACT_WALL_SLIDE, 0) + end + + --! Missing return statement (in original C code). The returned value is the result of the call + -- to set_mario_animation. In practice, this value is nonzero. + -- This results in this action "cancelling" into itself. It is supposed to + -- execute three times, each on a separate frame, but instead it executes + -- three times on the same frame. + -- This results in firsties only being possible for a single frame, instead + -- of three. + return set_mario_animation(m, MARIO_ANIM_START_WALLKICK) +end + ------------------------ -- water ground pound -- ------------------------ @@ -875,7 +894,7 @@ function act_water_ground_pound_jump(m) set_swimming_at_surface_particles(m, PARTICLE_WAVE_TRAIL) e.rotAngle = e.rotAngle + (0x10000*1.0 - e.rotAngle) / 5.0 - m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y - e.rotAngle + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - e.rotAngle) return 0 end @@ -965,6 +984,338 @@ function act_ground_pound_jump(m) return 0 end +------------------------------------- +-- dive slide patched for dive hop -- +------------------------------------- + +function act_dive_slide(m) + if (m.input & INPUT_ABOVE_SLIDE) == 0 and (m.input & INPUT_A_PRESSED) ~= 0 then + queue_rumble_data_mario(m, 5, 80) + if m.forwardVel > 0 then + return set_mario_action(m, ACT_FORWARD_ROLLOUT, 0) + else + return set_mario_action(m, ACT_BACKWARD_ROLLOUT, 0) + end + end + + if (m.input & INPUT_ABOVE_SLIDE) == 0 then + if (m.input & INPUT_B_PRESSED) ~= 0 then + -- dive hop + m.vel.y = 21.0 + return set_mario_action(m, ACT_DIVE, 1) + end + end + + play_mario_landing_sound_once(m, SOUND_ACTION_TERRAIN_BODY_HIT_GROUND) + + --! If the dive slide ends on the same frame that we pick up on object, + -- Mario will not be in the dive slide action for the call to + -- mario_check_object_grab, and so will end up in the regular picking action, + -- rather than the picking up after dive action. + + if update_sliding(m, 8.0) ~= 0 and is_anim_at_end(m) ~= 0 then + mario_set_forward_vel(m, 0.0) + set_mario_action(m, ACT_STOMACH_SLIDE_STOP, 0) + end + + if mario_check_object_grab(m) ~= 0 then + mario_grab_used_object(m) + if m.heldObj ~= 0 then + m.marioBodyState.grabPos = GRAB_POS_LIGHT_OBJ + end + return true + end + + common_slide_action(m, ACT_STOMACH_SLIDE_STOP, ACT_FREEFALL, MARIO_ANIM_DIVE) + return false +end + +------------------------------------------------------- +-- Patched actions using update_walking_speed action -- +-- for Tight Controls and modfied speed caps -- +------------------------------------------------------- + +function update_walking_speed_extended(m) + local maxTargetSpeed = 0 + local targetSpeed = 0 + local firmSpeedCap = 0 + local hardSpeedCap = 105.0 + + if m.prevAction == ACT_ROLL then + firmSpeedCap = 60.0 + else + firmSpeedCap = 48.0 + end + + if m.floor ~= 0 and m.floor.type == SURFACE_SLOW then + maxTargetSpeed = 24.0 + else + maxTargetSpeed = 32.0 + end + + if m.intendedMag < maxTargetSpeed then + targetSpeed = m.intendedMag + else + targetSpeed = maxTargetSpeed + end + + if m.quicksandDepth > 10.0 then + targetSpeed = targetSpeed * (6.25 / m.quicksandDepth) + end + + if m.forwardVel <= 8.0 then + m.forwardVel = math.min(m.intendedMag, 8.0) -- Same fix as Melee dashback (by Kaze) + end + + -- instead of a hard walk speed cap, going over this new firm speed cap makes you slow down to it twice as fast + local decayFactor = 0 + if m.forwardVel > firmSpeedCap then + decayFactor = 2.0 + else + decayFactor = 1.0 + end + + if m.forwardVel <= 0.0 then + m.forwardVel = m.forwardVel + 1.1 + elseif m.forwardVel <= targetSpeed then + m.forwardVel = m.forwardVel + (1.1 - m.forwardVel / 43.0) + elseif m.floor ~= 0 and m.floor.normal.y >= 0.95 then + m.forwardVel = m.forwardVel - decayFactor + else + -- reintroduce the old hardcap for the weird slopes where you kind of just maintain your speed + if (m.forwardVel > firmSpeedCap) then + m.forwardVel = firmSpeedCap; + end + end + + if m.forwardVel > hardSpeedCap then + m.forwardVel = hardSpeedCap + end + + if analog_stick_held_back(m) ~= 0 then + m.faceAngle.y = m.intendedYaw; + + if m.forwardVel < 0 then + mario_set_forward_vel(m, -m.forwardVel); + end + else + m.faceAngle.y = m.intendedYaw - approach_s32(limit_angle(m.intendedYaw - m.faceAngle.y), 0, 0xC00, 0xC00); + end + + apply_slope_accel(m) +end + +function act_walking(m) + local startPos = m.pos + local startYaw = m.faceAngle.y + + mario_drop_held_object(m) + + if should_begin_sliding(m) ~= 0 then + return set_mario_action(m, ACT_BEGIN_SLIDING, 0) + end + + if (m.input & INPUT_FIRST_PERSON) ~= 0 then + return begin_braking_action(m) + end + + if (m.input & INPUT_A_PRESSED) ~= 0 then + return set_jump_from_landing(m) + end + + if check_ground_dive_or_punch(m) ~= 0 then + return true + end + + if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then + return begin_braking_action(m) + end + + if analog_stick_held_back(m) ~= 0 and m.forwardVel >= 12.0 then + return set_mario_action(m, ACT_TURNING_AROUND, 0) + end + + if (m.input & INPUT_Z_PRESSED) ~= 0 then + return set_mario_action(m, ACT_CROUCH_SLIDE, 0) + end + + m.actionState = 0 + + vec3f_copy(startPos, m.pos) + update_walking_speed_extended(m) + + local stepResult = perform_ground_step(m) + if stepResult == GROUND_STEP_LEFT_GROUND then + set_mario_action(m, ACT_FREEFALL, 0) + set_mario_animation(m, MARIO_ANIM_GENERAL_FALL) + elseif stepResult == GROUND_STEP_NONE then + anim_and_audio_for_walk(m) + if (m.intendedMag - m.forwardVel > 16.0) then + m.particleFlags = m.particleFlags | PARTICLE_DUST + end + elseif stepResult == GROUND_STEP_HIT_WALL then + push_or_sidle_wall(m, startPos) + m.actionTimer = 0 + end + + check_ledge_climb_down(m) + tilt_body_walking(m, startYaw) + return false +end + +function act_hold_walking(m) + if m.heldObj.behavior == bhvJumpingBox then + return set_mario_action(m, ACT_CRAZY_BOX_BOUNCE, 0) + end + + if (m.marioObj.oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) ~= 0 then + return drop_and_set_mario_action(m, ACT_WALKING, 0) + end + + if should_begin_sliding(m) ~= 0 then + return set_mario_action(m, ACT_HOLD_BEGIN_SLIDING, 0) + end + + if (m.input & INPUT_B_PRESSED) ~= 0 then + return set_mario_action(m, ACT_THROWING, 0) + end + + if (m.input & INPUT_A_PRESSED) ~= 0 then + return set_jumping_action(m, ACT_HOLD_JUMP, 0) + end + + if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then + return set_mario_action(m, ACT_HOLD_DECELERATING, 0) + end + + if (m.input & INPUT_Z_PRESSED) ~= 0 then + return drop_and_set_mario_action(m, ACT_CROUCH_SLIDE, 0) + end + + m.intendedMag = m.intendedMag * 0.4 + + update_walking_speed_extended(m) + + local stepResult = perform_ground_step(m) + if stepResult == GROUND_STEP_LEFT_GROUND then + set_mario_action(m, ACT_HOLD_FREEFALL, 0) + elseif stepResult == GROUND_STEP_HIT_WALL then + if m.forwardVel > 16.0 then + mario_set_forward_vel(m, 16.0) + end + end + + anim_and_audio_for_hold_walk(m) + + if 0.4 * m.intendedMag - m.forwardVel > 10.0 then + m.particleFlags = m.particleFlags | PARTICLE_DUST + end + + return false +end + +function act_hold_heavy_walking(m) + if (m.input & INPUT_B_PRESSED) ~= 0 then + return set_mario_action(m, ACT_HEAVY_THROW, 0) + end + + if should_begin_sliding(m) ~= 0 then + return drop_and_set_mario_action(m, ACT_BEGIN_SLIDING, 0) + end + + if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then + return set_mario_action(m, ACT_HOLD_HEAVY_IDLE, 0) + end + + m.intendedMag = m.intendedMag * 0.1 + + update_walking_speed_extended(m) + + local stepResult = perform_ground_step(m) + if stepResult == GROUND_STEP_LEFT_GROUND then + drop_and_set_mario_action(m, ACT_FREEFALL, 0) + elseif stepResult == GROUND_STEP_HIT_WALL then + if (m.forwardVel > 10.0) then + mario_set_forward_vel(m, 10.0) + end + end + + anim_and_audio_for_heavy_walk(m) + return false +end + +function act_finish_turning_around(m) + if (m.input & INPUT_ABOVE_SLIDE) ~= 0 then + return set_mario_action(m, ACT_BEGIN_SLIDING, 0) + end + + if (m.input & INPUT_A_PRESSED) ~= 0 then + return set_jumping_action(m, ACT_SIDE_FLIP, 0) + end + + update_walking_speed_extended(m) + set_mario_animation(m, MARIO_ANIM_TURNING_PART2) + + if perform_ground_step(m) == GROUND_STEP_LEFT_GROUND then + set_mario_action(m, ACT_FREEFALL, 0) + end + + if is_anim_at_end(m) ~= 0 then + set_mario_action(m, ACT_WALKING, 0) + end + + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + 0x8000) + return false +end + +function act_crawling(m) + if should_begin_sliding(m) ~= 0 then + return set_mario_action(m, ACT_BEGIN_SLIDING, 0) + end + + if (m.input & INPUT_FIRST_PERSON) ~= 0 then + return set_mario_action(m, ACT_STOP_CRAWLING, 0) + end + + if (m.input & INPUT_A_PRESSED) ~= 0 then + return set_jumping_action(m, ACT_JUMP, 0) + end + + if check_ground_dive_or_punch(m) ~= 0 then + return true + end + + if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then + return set_mario_action(m, ACT_STOP_CRAWLING, 0) + end + + if (m.input & INPUT_Z_DOWN) == 0 then + return set_mario_action(m, ACT_STOP_CRAWLING, 0) + end + + m.intendedMag = m.intendedMag * 0.1 + + update_walking_speed_extended(m) + + local stepResult = perform_ground_step(m) + if stepResult == GROUND_STEP_LEFT_GROUND then + set_mario_action(m, ACT_FREEFALL, 0) + elseif stepResult == GROUND_STEP_HIT_WALL then + if m.forwardVel > 10.0 then + mario_set_forward_vel(m, 10.0) + end + --! Possibly unintended missing break + align_with_floor(m) + elseif stepResult == GROUND_STEP_NONE then + align_with_floor(m) + end + + local val04 = (m.intendedMag * 2.0 * 0x10000) + set_mario_anim_with_accel(m, MARIO_ANIM_CRAWLING, val04) + play_step_sound(m, 26, 79) + return false +end + --------------------------------------------------------- function mario_on_set_action(m) @@ -974,30 +1325,26 @@ function mario_on_set_action(m) e.savedWallSlide = false end - if e.spinInput ~= 0 then - if m.action == ACT_JUMP or m.action == ACT_DOUBLE_JUMP or m.action == ACT_TRIPLE_JUMP or m.action == ACT_SPECIAL_TRIPLE_JUMP or m.action == ACT_SIDE_FLIP or m.action == ACT_BACKFLIP or m.action == ACT_WALL_KICK_AIR then + if e.spinInput ~= 0 and (m.input & INPUT_ABOVE_SLIDE) == 0 then + if m.action == ACT_JUMP or + m.action == ACT_DOUBLE_JUMP or + m.action == ACT_TRIPLE_JUMP or + m.action == ACT_SPECIAL_TRIPLE_JUMP or + m.action == ACT_SIDE_FLIP or + m.action == ACT_BACKFLIP then set_mario_action(m, ACT_SPIN_JUMP, 1) m.vel.y = 65.0 m.faceAngle.y = m.intendedYaw end end - if m.action == ACT_GROUND_POUND_JUMP then - m.vel.y = 65.0 - elseif m.action == ACT_SOFT_BONK then - m.faceAngle.y = m.faceAngle.y + 0x8000 - m.pos.x = e.lastPos.x - m.pos.y = e.lastPos.y - m.pos.z = e.lastPos.z - set_mario_action(m, ACT_WALL_SLIDE, 0) - m.vel.x = 0 - m.vel.y = 0 - m.vel.z = 0 - elseif m.action == ACT_WATER_PLUNGE and m.prevAction == ACT_GROUND_POUND then + if m.action == ACT_WATER_PLUNGE and m.prevAction == ACT_GROUND_POUND then return set_mario_action(m, ACT_WATER_GROUND_POUND, 1) + elseif m.action == ACT_WALL_SLIDE then + m.vel.y = 0.0 elseif m.action == ACT_GROUND_POUND and m.prevAction == ACT_SIDE_FLIP then -- correct animation - m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y - 0x8000 + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - 0x8000) elseif m.action == ACT_LEDGE_GRAB then e.rotAngle = m.forwardVel end @@ -1034,15 +1381,6 @@ function mario_update(m) mario_update_spin_input(m) update_roll(m) - -- dive hop - if (m.input & INPUT_B_PRESSED) ~= 0 and (m.input & INPUT_ABOVE_SLIDE) == 0 then - if m.action == ACT_FORWARD_ROLLOUT and m.prevAction == ACT_DIVE_SLIDE then - m.vel.y = 21.0 - return set_mario_action(m, ACT_DIVE, 1) - - end - end - -- dive out of ACT_GROUND_POUND if m.action == ACT_GROUND_POUND and (m.input & INPUT_B_PRESSED) ~= 0 then mario_set_forward_vel(m, 10.0) @@ -1051,7 +1389,11 @@ function mario_update(m) end -- spin - if (m.action == ACT_JUMP or m.action == ACT_WALL_KICK_AIR) and e.spinInput ~= 0 then + if (m.action == ACT_JUMP or + m.action == ACT_WALL_KICK_AIR or + m.action == ACT_DOUBLE_JUMP or + m.action == ACT_BACKFLIP or + m.action == ACT_SIDE_FLIP) and e.spinInput ~= 0 then set_mario_action(m, ACT_SPIN_JUMP, 1) e.spinInput = 0 end @@ -1076,7 +1418,7 @@ function mario_update(m) -- maintain spinning from water ground pound jump anim if m.action == ACT_WATER_JUMP and m.prevAction == ACT_WATER_GROUND_POUND_JUMP then e.rotAngle = e.rotAngle + (0x10000*1.0 - e.rotAngle) / 5.0 - m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y - e.rotAngle + m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - e.rotAngle) end -- edge parkour @@ -1106,15 +1448,22 @@ hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update) hook_event(HOOK_MARIO_UPDATE, mario_update) hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action) -hook_mario_action(ACT_ROLL, act_roll) -hook_mario_action(ACT_ROLL_AIR, act_roll_air) -hook_mario_action(ACT_SPIN_JUMP, act_spin_jump) -hook_mario_action(ACT_SPIN_POUND, act_spin_pound) -hook_mario_action(ACT_SPIN_POUND_LAND, act_spin_pound_land) -hook_mario_action(ACT_GROUND_POUND_JUMP, act_ground_pound_jump) -hook_mario_action(ACT_WALL_SLIDE, act_wall_slide) -hook_mario_action(ACT_WATER_GROUND_POUND, act_water_ground_pound) -hook_mario_action(ACT_WATER_GROUND_POUND_LAND, act_water_ground_pound_land) -hook_mario_action(ACT_WATER_GROUND_POUND_STROKE, act_water_ground_pound_stroke) -hook_mario_action(ACT_WATER_GROUND_POUND_JUMP, act_water_ground_pound_jump) -hook_mario_action(ACT_LEDGE_PARKOUR, act_ledge_parkour) +hook_mario_action(ACT_ROLL, { every_frame = act_roll }) +hook_mario_action(ACT_ROLL_AIR, { every_frame = act_roll_air }) +hook_mario_action(ACT_SPIN_JUMP, { every_frame = act_spin_jump, gravity = act_spin_jump_gravity }) +hook_mario_action(ACT_SPIN_POUND, { every_frame = act_spin_pound }) +hook_mario_action(ACT_SPIN_POUND_LAND, { every_frame = act_spin_pound_land }) +hook_mario_action(ACT_GROUND_POUND_JUMP, { every_frame = act_ground_pound_jump }) +hook_mario_action(ACT_WALL_SLIDE, { every_frame = act_wall_slide, gravity = act_wall_slide_gravity }) +hook_mario_action(ACT_WATER_GROUND_POUND, { every_frame = act_water_ground_pound }) +hook_mario_action(ACT_WATER_GROUND_POUND_LAND, { every_frame = act_water_ground_pound_land }) +hook_mario_action(ACT_WATER_GROUND_POUND_STROKE, { every_frame = act_water_ground_pound_stroke }) +hook_mario_action(ACT_WATER_GROUND_POUND_JUMP, { every_frame = act_water_ground_pound_jump }) +hook_mario_action(ACT_LEDGE_PARKOUR, { every_frame = act_ledge_parkour }) +hook_mario_action(ACT_DIVE_SLIDE, { every_frame = act_dive_slide }) +hook_mario_action(ACT_WALKING, { every_frame = act_walking }) +hook_mario_action(ACT_HOLD_WALKING, { every_frame = act_hold_walking }) +hook_mario_action(ACT_HOLD_HEAVY_WALKING, { every_frame = act_hold_heavy_walking }) +hook_mario_action(ACT_FINISH_TURNING_AROUND, { every_frame = act_finish_turning_around }) +hook_mario_action(ACT_CRAWLING, { every_frame = act_crawling }) +hook_mario_action(ACT_AIR_HIT_WALL, { every_frame = act_air_hit_wall }) diff --git a/mods/shell-rush/actions.lua b/mods/shell-rush/actions.lua index eb08d04d9..31cc1084b 100644 --- a/mods/shell-rush/actions.lua +++ b/mods/shell-rush/actions.lua @@ -273,6 +273,6 @@ function act_race_shell_air(m) return 0 end -hook_mario_action(ACT_RIDING_SHELL_GROUND, act_race_shell_ground) -hook_mario_action(ACT_RIDING_SHELL_JUMP, act_race_shell_air) -hook_mario_action(ACT_RIDING_SHELL_FALL, act_race_shell_air) +hook_mario_action(ACT_RIDING_SHELL_GROUND, { every_frame = act_race_shell_ground }) +hook_mario_action(ACT_RIDING_SHELL_JUMP, { every_frame = act_race_shell_air }) +hook_mario_action(ACT_RIDING_SHELL_FALL, { every_frame = act_race_shell_air }) diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 6990d10db..bec7eacdf 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -2200,7 +2200,7 @@ s32 mario_execute_airborne_action(struct MarioState *m) { play_far_fall_sound(m); - if (!smlua_call_action_hook(m, (s32*)&cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, (s32*)&cancel)) { /* clang-format off */ switch (m->action) { case ACT_JUMP: cancel = act_jump(m); break; diff --git a/src/game/mario_actions_automatic.c b/src/game/mario_actions_automatic.c index 8582b8cfe..9b0466ee6 100644 --- a/src/game/mario_actions_automatic.c +++ b/src/game/mario_actions_automatic.c @@ -1072,7 +1072,7 @@ s32 mario_execute_automatic_action(struct MarioState *m) { m->quicksandDepth = 0.0f; - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_HOLDING_POLE: cancel = act_holding_pole(m); break; diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index d62e9fe7a..874fc2186 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -2974,7 +2974,7 @@ s32 mario_execute_cutscene_action(struct MarioState *m) { return TRUE; } - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_DISAPPEARED: cancel = act_disappeared(m); break; diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 1c13b2186..88154e00e 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -2002,7 +2002,7 @@ s32 mario_execute_moving_action(struct MarioState *m) { return TRUE; } - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_WALKING: cancel = act_walking(m); break; diff --git a/src/game/mario_actions_object.c b/src/game/mario_actions_object.c index 21bf0061a..fb9fb09ca 100644 --- a/src/game/mario_actions_object.c +++ b/src/game/mario_actions_object.c @@ -493,7 +493,7 @@ s32 mario_execute_object_action(struct MarioState *m) { return TRUE; } - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_PUNCHING: cancel = act_punching(m); break; diff --git a/src/game/mario_actions_stationary.c b/src/game/mario_actions_stationary.c index 2dc20e29c..a3e69ff8f 100644 --- a/src/game/mario_actions_stationary.c +++ b/src/game/mario_actions_stationary.c @@ -1130,7 +1130,7 @@ s32 mario_execute_stationary_action(struct MarioState *m) { return TRUE; } - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_IDLE: cancel = act_idle(m); break; diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 531a3239d..a6d3d340e 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -1593,7 +1593,7 @@ s32 mario_execute_submerged_action(struct MarioState *m) { m->marioBodyState->headAngle[1] = 0; m->marioBodyState->headAngle[2] = 0; - if (!smlua_call_action_hook(m, &cancel)) { + if (!smlua_call_action_hook(ACTION_HOOK_EVERY_FRAME, m, &cancel)) { /* clang-format off */ switch (m->action) { case ACT_WATER_IDLE: cancel = act_water_idle(m); break; diff --git a/src/game/mario_step.c b/src/game/mario_step.c index f20ee23df..ba1507b1b 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -594,6 +594,8 @@ u32 should_strengthen_gravity_for_jump_ascent(struct MarioState *m) { } void apply_gravity(struct MarioState *m) { + s32 result; + if (m->action == ACT_TWIRLING && m->vel[1] < 0.0f) { apply_twirl_gravity(m); } else if (m->action == ACT_SHOT_FROM_CANNON) { @@ -624,6 +626,8 @@ void apply_gravity(struct MarioState *m) { if (m->vel[1] < -16.0f) { m->vel[1] = -16.0f; } + } else if (smlua_call_action_hook(ACTION_HOOK_GRAVITY, m, &result)) { + } else if ((m->flags & MARIO_WING_CAP) && m->vel[1] < 0.0f && (m->input & INPUT_A_DOWN)) { m->marioBodyState->wingFlutter = TRUE; diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 09cf78397..5e345ec78 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -2819,8 +2819,10 @@ char gSmluaConstants[] = "" "HOOK_ON_OBJECT_RENDER = 20\n" "HOOK_ON_DEATH = 21\n" "HOOK_ON_PACKET_RECEIVE = 22\n" -"HOOK_USE_ACT_SELECT = 23\n" -"HOOK_MAX = 24\n" +"HOOK_MAX = 23\n" +"ACTION_HOOK_EVERY_FRAME = 0\n" +"ACTION_HOOK_GRAVITY = 1\n" +"ACTION_HOOK_MAX = 2\n" "HUD_DISPLAY_LIVES = 0\n" "HUD_DISPLAY_COINS = 1\n" "HUD_DISPLAY_STARS = 2\n" diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index bd7f58efb..e20f69c8c 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -533,7 +533,7 @@ void smlua_call_event_hooks_use_act_select(enum LuaHookedEventType hookType, int struct LuaHookedMarioAction { u32 action; u32 interactionType; - int reference; + int actionHookRefs[ACTION_HOOK_MAX]; struct Mod* mod; }; @@ -565,11 +565,11 @@ int smlua_hook_mario_action(lua_State* L) { return 0; } - lua_pushvalue(L, 2); - int ref = luaL_ref(L, LUA_REGISTRYINDEX); + int secondParamType = lua_type(L, 2); + bool oldApi = secondParamType == LUA_TFUNCTION; - if (ref == -1) { - LOG_LUA_LINE("Hook Action: %lld tried to hook undefined function", action); + if (!oldApi && secondParamType != LUA_TTABLE) { + LOG_LUA_LINE("smlua_hook_mario_action received improper type '%d'", lua_type(L, 2)); return 0; } @@ -583,9 +583,45 @@ int smlua_hook_mario_action(lua_State* L) { } struct LuaHookedMarioAction* hooked = &sHookedMarioActions[sHookedMarioActionsCount]; + + // Support calling the function with just one function corresponding to the "every frame" hook instead of a full + // table with all hooks + if (oldApi) { + for (int i = 0; i < ACTION_HOOK_MAX; i++) { + hooked->actionHookRefs[i] = LUA_NOREF; + } + + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if (ref == -1) { + LOG_LUA_LINE("Hook Action: %lld tried to hook undefined function", action); + return 0; + } + + hooked->actionHookRefs[ACTION_HOOK_EVERY_FRAME] = ref; + } + else { + for (int i = 0; i < ACTION_HOOK_MAX; i++) { + lua_pushstring(L, LuaActionHookTypeArgName[i]); + + if (lua_gettable(L, 2) == LUA_TNIL) { + hooked->actionHookRefs[i] = LUA_NOREF; + } else { + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if (ref == -1) { + LOG_LUA_LINE("Hook Action: %lld tried to hook undefined function", action); + return 0; + } + + hooked->actionHookRefs[i] = ref; + } + } + } + hooked->action = action; hooked->interactionType = interactionType; - hooked->reference = ref; hooked->mod = gLuaActiveMod; if (!gSmLuaConvertSuccess) { return 0; } @@ -593,14 +629,16 @@ int smlua_hook_mario_action(lua_State* L) { return 1; } -bool smlua_call_action_hook(struct MarioState* m, s32* returnValue) { +bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState* m, s32* returnValue) { lua_State* L = gLuaState; if (L == NULL) { return false; } + + //TODO GAG: Set up things such that O(n) check isn't performed on every action hook? Maybe in MarioState? for (int i = 0; i < sHookedMarioActionsCount; i++) { struct LuaHookedMarioAction* hook = &sHookedMarioActions[i]; - if (hook->action == m->action) { + if (hook->action == m->action && hook->actionHookRefs[hookType] != LUA_NOREF) { // push the callback onto the stack - lua_rawgeti(L, LUA_REGISTRYINDEX, hook->reference); + lua_rawgeti(L, LUA_REGISTRYINDEX, hook->actionHookRefs[hookType]); // push mario state lua_getglobal(L, "gMarioStates"); @@ -1084,7 +1122,7 @@ void smlua_clear_hooks(void) { struct LuaHookedMarioAction* hooked = &sHookedMarioActions[i]; hooked->action = 0; hooked->mod = NULL; - hooked->reference = 0; + memset(hooked->actionHookRefs, 0, sizeof(hooked->actionHookRefs)); } sHookedMarioActionsCount = 0; diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 2da70c136..07e26c329 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -66,6 +66,18 @@ static const char* LuaHookedEventTypeName[] = { "HOOK_MAX" }; +enum LuaActionHookType { + ACTION_HOOK_EVERY_FRAME, + ACTION_HOOK_GRAVITY, + ACTION_HOOK_MAX, +}; + +static const char* LuaActionHookTypeArgName[] = { + "every_frame", + "gravity", + "max (dummy)", +}; + extern u32 gLuaMarioActionIndex; int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName); @@ -92,7 +104,7 @@ bool smlua_is_behavior_hooked(const BehaviorScript *behavior); bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* object, bool before); int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod); -bool smlua_call_action_hook(struct MarioState* m, s32* returnValue); +bool smlua_call_action_hook(enum LuaActionHookType hookType, struct MarioState* m, s32* returnValue); u32 smlua_get_action_interaction_type(struct MarioState* m); bool smlua_call_chat_command_hook(char* command); diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index af58f5389..ed6d45cd9 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -273,7 +273,7 @@ bool is_game_paused(void) { /// u32 allocate_mario_action(u32 actFlags) { - actFlags = actFlags & (~((u32)0xFF)); + actFlags = actFlags & (~((u32)0x3F)); return actFlags | ACT_FLAG_CUSTOM_ACTION | gLuaMarioActionIndex++; }