Add Wario's moveset based on steven's mod

This commit is contained in:
MysterD 2022-02-14 18:26:44 -08:00
parent 3436d6d26f
commit 6d6d94fcde
11 changed files with 608 additions and 24 deletions

View file

@ -16,6 +16,7 @@ in_files = [
"src/game/characters.h", "src/game/characters.h",
"src/pc/network/network_player.h", "src/pc/network/network_player.h",
"include/PR/os_cont.h", "include/PR/os_cont.h",
"src/game/interaction.c",
] ]
exclude_constants = [ exclude_constants = [
@ -23,6 +24,8 @@ exclude_constants = [
'^LEVEL_.*', '^LEVEL_.*',
'^AREA_.*', '^AREA_.*',
'^CONT_ERR.*', '^CONT_ERR.*',
'^READ_MASK$',
'^SIGN_RANGE$',
] ]
pretend_find = [ pretend_find = [

View file

@ -130,6 +130,21 @@ function approach_f32(current, target, inc, dec)
return current; return current;
end end
function approach_s32(current, target, inc, dec)
if current < target then
current = current + inc
if current > target then
current = target
end
else
current = current - dec
if current < target then
current = target
end
end
return current;
end
function SOUND_ARG_LOAD(bank, playFlags, soundID, priority, flags2) function SOUND_ARG_LOAD(bank, playFlags, soundID, priority, flags2)
return ((bank << 28) | (playFlags << 24) | (soundID << 16) | (priority << 8) | (flags2 << 4) | 1) return ((bank << 28) | (playFlags << 24) | (soundID << 16) | (priority << 8) | (flags2 << 4) | 1)
end end

View file

@ -6,6 +6,8 @@
- [characters.h](#characters.h) - [characters.h](#characters.h)
- [CharacterSound](#CharacterSound) - [CharacterSound](#CharacterSound)
- [CharacterType](#CharacterType) - [CharacterType](#CharacterType)
- [interaction.c](#interaction.c)
- [InteractionFlag](#InteractionFlag)
- [mario_animation_ids.h](#mario_animation_ids.h) - [mario_animation_ids.h](#mario_animation_ids.h)
- [MarioAnimID](#MarioAnimID) - [MarioAnimID](#MarioAnimID)
- [network_player.h](#network_player.h) - [network_player.h](#network_player.h)
@ -740,6 +742,26 @@
<br /> <br />
## [interaction.c](#interaction.c)
- INT_ANY_ATTACK
- INT_ATTACK_NOT_FROM_BELOW
- INT_ATTACK_NOT_WEAK_FROM_ABOVE
- INT_ATTACK_SLIDE
### [enum InteractionFlag](#InteractionFlag)
| Identifier | Value |
| :--------- | :---- |
| INT_GROUND_POUND_OR_TWIRL | (1 << 0) |
| INT_PUNCH | (1 << 1) |
| INT_KICK | (1 << 2) |
| INT_TRIP | (1 << 3) |
| INT_SLIDE_KICK | (1 << 4) |
| INT_FAST_ATTACK_OR_SHELL | (1 << 5) |
| INT_HIT_FROM_ABOVE | (1 << 6) |
| INT_HIT_FROM_BELOW | (1 << 7) |
<br />
## [mario_animation_ids.h](#mario_animation_ids.h) ## [mario_animation_ids.h](#mario_animation_ids.h)
### [enum MarioAnimID](#MarioAnimID) ### [enum MarioAnimID](#MarioAnimID)

View file

@ -84,6 +84,7 @@ hook_event(HOOK_MARIO_UPDATE, mario_update)
| ----- | ---- | | ----- | ---- |
| action_id | integer | | action_id | integer |
| func | Lua Function | | func | Lua Function |
| interaction_type | [enum InteractionFlag](constants.md#InteractionFlag) <optional> |
### Lua Example ### Lua Example

View file

@ -2,11 +2,22 @@
-- incompatible: moveset -- incompatible: moveset
-- description: Gives each character unique abilities and stats. -- description: Gives each character unique abilities and stats.
ANGLE_QUEUE_SIZE = 9
SPIN_TIMER_SUCCESSFUL_INPUT = 4
gEventTable = {}
gStateExtras = {} gStateExtras = {}
for i=0,(MAX_PLAYERS-1) do for i=0,(MAX_PLAYERS-1) do
gStateExtras[i] = {} gStateExtras[i] = {}
local m = gMarioStates[i] local m = gMarioStates[i]
local e = gStateExtras[i] local e = gStateExtras[i]
e.prevPos = {}
e.prevPos.x = 0
e.prevPos.y = 0
e.prevPos.z = 0
e.angleDeltaQueue = {}
for j=0,(ANGLE_QUEUE_SIZE-1) do e.angleDeltaQueue[j] = 0 end
e.lastAction = m.action e.lastAction = m.action
e.animFrame = 0 e.animFrame = 0
e.scuttle = 0 e.scuttle = 0
@ -14,18 +25,20 @@ for i=0,(MAX_PLAYERS-1) do
e.boostTimer = 0 e.boostTimer = 0
e.rotAngle = 0 e.rotAngle = 0
e.lastHurtCounter = 0 e.lastHurtCounter = 0
e.stickLastAngle = 0
e.spinDirection = 0
e.spinBufferTimer = 0
e.spinInput = 0
e.lastIntendedMag = 0
end end
gEventTable = {}
ACT_SPIN_POUND_LAND = (0x037 | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING)
ACT_SPIN_POUND = (0x08F | ACT_FLAG_AIR | ACT_FLAG_ATTACKING)
----------- -----------
-- luigi -- -- luigi --
----------- -----------
ACT_SPIN_POUND_LAND = (0x037 | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING)
ACT_SPIN_POUND = (0x08F | ACT_FLAG_AIR | ACT_FLAG_ATTACKING)
function act_spin_pound(m) function act_spin_pound(m)
local e = gStateExtras[m.playerIndex] local e = gStateExtras[m.playerIndex]
if m.actionTimer == 0 then if m.actionTimer == 0 then
@ -303,6 +316,8 @@ end
function toad_update(m) function toad_update(m)
local e = gStateExtras[m.playerIndex] local e = gStateExtras[m.playerIndex]
-- track average forward velocity
if e.averageForwardVel > m.forwardVel then if e.averageForwardVel > m.forwardVel then
e.averageForwardVel = e.averageForwardVel * 0.93 + m.forwardVel * 0.07 e.averageForwardVel = e.averageForwardVel * 0.93 + m.forwardVel * 0.07
else else
@ -331,9 +346,9 @@ gEventTable[CT_TOAD] = {
update = toad_update, update = toad_update,
} }
----------- -------------
-- waluigi -- -- waluigi --
----------- -------------
ACT_WALL_SLIDE = (0x0BF | ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) ACT_WALL_SLIDE = (0x0BF | ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
@ -453,6 +468,439 @@ gEventTable[CT_WALUIGI] = {
update = waluigi_update, update = waluigi_update,
} }
-----------
-- wario --
-----------
ACT_WARIO_DASH = (0x05B | ACT_FLAG_MOVING | ACT_FLAG_ATTACKING)
ACT_WARIO_AIR_DASH = (0x05B | ACT_FLAG_AIR | ACT_FLAG_ATTACKING)
ACT_CORKSCREW_CONK = (0x05D | ACT_FLAG_AIR | ACT_FLAG_ATTACKING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
ACT_WARIO_SPINNING_OBJ = (0x05B | ACT_FLAG_STATIONARY)
function act_corkscrew_conk(m)
local e = gStateExtras[m.playerIndex]
m.particleFlags = m.particleFlags | PARTICLE_DUST
common_air_action_step(m, ACT_JUMP_LAND, MARIO_ANIM_FORWARD_SPINNING, AIR_STEP_NONE)
set_anim_to_frame(m, e.animFrame)
if e.animFrame >= m.marioObj.header.gfx.animInfo.curAnim.loopEnd then
e.animFrame = e.animFrame - m.marioObj.header.gfx.animInfo.curAnim.loopEnd
end
if (m.input & INPUT_Z_PRESSED) ~= 0 then
local rc = set_mario_action(m, ACT_GROUND_POUND, 0)
m.actionTimer = 5
return rc
end
m.actionTimer = m.actionTimer + 1
e.animFrame = e.animFrame + 1
return 0
end
function act_wario_dash(m)
local e = gStateExtras[m.playerIndex]
-- when hitting wall, stay dashing for an extra frame
if m.actionArg == 99 then
m.actionTimer = m.actionTimer + 1
if m.actionTimer > 2 then
return set_mario_action(m, ACT_WALKING, 0)
end
return 0
end
-- make sound
if m.actionTimer == 0 then
m.actionState = m.actionArg
play_character_sound(m, CHAR_SOUND_YAHOO)
end
-- walk once dash is up
if m.actionTimer > 15 then
return set_mario_action(m, ACT_WALKING, 0)
end
-- slide and set animation
common_slide_action(m, ACT_DIVE, ACT_MOVE_PUNCHING, MARIO_ANIM_FIRST_PUNCH)
set_anim_to_frame(m, 25)
-- set dash speed
local speed = 100
if m.actionTimer > 8 then
speed = speed - (m.actionTimer - 8) * 11
end
mario_set_forward_vel(m, speed)
-- corkscrew conk
if (m.input & INPUT_A_PRESSED) ~= 0 then
set_jumping_action(m, ACT_CORKSCREW_CONK, 0)
play_character_sound(m, CHAR_SOUND_YAHOO)
end
-- slide kick
if (m.input & INPUT_Z_PRESSED) ~= 0 then
return set_mario_action(m, ACT_SLIDE_KICK, 0)
end
m.actionTimer = m.actionTimer + 1
return 0
end
function act_wario_air_dash(m)
local e = gStateExtras[m.playerIndex]
-- walk once dash is up
if m.actionTimer > 15 then
return set_mario_action(m, ACT_JUMP_LAND, 0)
end
-- slide and set animation
common_air_action_step(m, ACT_JUMP_LAND, MARIO_ANIM_FIRST_PUNCH, AIR_STEP_NONE)
set_anim_to_frame(m, 25)
-- set dash speed
local speed = 100
if m.actionTimer > 8 then
speed = speed - (m.actionTimer - 8) * 11
end
mario_set_forward_vel(m, speed)
-- corkscrew conk
if (m.input & INPUT_A_PRESSED) ~= 0 then
set_jumping_action(m, ACT_CORKSCREW_CONK, 0)
play_character_sound(m, CHAR_SOUND_YAHOO)
end
-- slide kick
if (m.input & INPUT_Z_PRESSED) ~= 0 then
return set_mario_action(m, ACT_SLIDE_KICK, 0)
end
m.actionTimer = m.actionTimer + 1
return 0
end
function act_wario_spinning_obj(m)
local spin = 0
-- throw object
if m.playerIndex == 0 and (m.input & INPUT_B_PRESSED) ~= 0 then
play_character_sound_if_no_flag(m, CHAR_SOUND_WAH2, MARIO_MARIO_SOUND_PLAYED)
play_sound_if_no_flag(m, SOUND_ACTION_THROW, MARIO_ACTION_SOUND_PLAYED)
return set_mario_action(m, ACT_RELEASING_BOWSER, 0)
end
-- set animation
if m.playerIndex == 0 and m.angleVel.y == 0 then
m.actionTimer = m.actionTimer + 1
if m.actionTimer > 120 then
return set_mario_action(m, ACT_RELEASING_BOWSER, 1)
end
set_mario_animation(m, MARIO_ANIM_HOLDING_BOWSER)
else
m.actionTimer = 0
set_mario_animation(m, MARIO_ANIM_SWINGING_BOWSER)
end
-- spin
if m.intendedMag > 20.0 then
-- spin = acceleration
spin = (m.intendedYaw - m.twirlYaw) / 0x20
if spin < -0x80 then
spin = -0x80
end
if spin > 0x80 then
spin = 0x80
end
m.twirlYaw = m.intendedYaw
m.angleVel.y = m.angleVel.y + spin
if m.angleVel.y > 0x1000 then
m.angleVel.y = 0x1000
end
if m.angleVel.y < -0x1000 then
m.angleVel.y = -0x1000
end
elseif m.angleVel.y > -0x750 and m.angleVel.y < 0x750 then
-- go back to walking
return set_mario_action(m, ACT_HOLD_IDLE, 0)
else
-- slow down spin
m.angleVel.y = approach_s32(m.angleVel.y, 0, 128, 128);
end
-- apply spin
spin = m.faceAngle.y
m.faceAngle.y = m.faceAngle.y + m.angleVel.y
-- play sound on overflow
if m.angleVel.y <= -0x100 and spin < m.faceAngle.y then
queue_rumble_data_mario(m, 4, 20)
play_sound(SOUND_OBJ_BOWSER_SPINNING, m.marioObj.header.gfx.cameraToObject)
end
if m.angleVel.y >= 0x100 and spin > m.faceAngle.y then
queue_rumble_data_mario(m, 4, 20)
play_sound(SOUND_OBJ_BOWSER_SPINNING, m.marioObj.header.gfx.cameraToObject)
end
stationary_ground_step(m)
if m.angleVel.y >= 0 then
m.marioObj.header.gfx.angle.x = -m.angleVel.y
else
m.marioObj.header.gfx.angle.x = m.angleVel.y
end
return false
end
function wario_update_spin_input(m)
local e = gStateExtras[m.playerIndex]
local rawAngle = atan2s(-m.controller.stickY, m.controller.stickX)
e.spinInput = 0
-- prevent issues due to the frame going out of the dead zone registering the last angle as 0
if e.lastIntendedMag > 0.5 and m.intendedMag > 0.5 then
local angleOverFrames = 0
local thisFrameDelta = 0
local i = 0
local newDirection = e.spinDirection
local signedOverflow = 0
if rawAngle < e.stickLastAngle then
if (e.stickLastAngle - rawAngle) > 0x8000 then
signedOverflow = 1
end
if signedOverflow ~= 0 then
newDirection = 1
else
newDirection = -1
end
elseif rawAngle > e.stickLastAngle then
if (rawAngle - e.stickLastAngle) > 0x8000 then
signedOverflow = 1
end
if signedOverflow ~= 0 then
newDirection = -1
else
newDirection = 1
end
end
if e.spinDirection ~= newDirection then
for i=0,(ANGLE_QUEUE_SIZE-1) do
e.angleDeltaQueue[i] = 0
end
e.spinDirection = newDirection
else
for i=(ANGLE_QUEUE_SIZE-1),1,-1 do
e.angleDeltaQueue[i] = e.angleDeltaQueue[i-1]
angleOverFrames = angleOverFrames + e.angleDeltaQueue[i]
end
end
if e.spinDirection < 0 then
if signedOverflow ~= 0 then
thisFrameDelta = math.floor((1.0*e.stickLastAngle + 0x10000) - rawAngle)
else
thisFrameDelta = e.stickLastAngle - rawAngle
end
elseif e.spinDirection > 0 then
if signedOverflow ~= 0 then
thisFrameDelta = math.floor(1.0*rawAngle + 0x10000 - e.stickLastAngle)
else
thisFrameDelta = rawAngle - e.stickLastAngle
end
end
e.angleDeltaQueue[0] = thisFrameDelta
angleOverFrames = angleOverFrames + thisFrameDelta
if angleOverFrames >= 0xA000 then
e.spinBufferTimer = SPIN_TIMER_SUCCESSFUL_INPUT
end
-- allow a buffer after a successful input so that you can switch directions
if e.spinBufferTimer > 0 then
e.spinInput = 1
e.spinBufferTimer = e.spinBufferTimer - 1
end
else
e.spinDirection = 0
e.spinBufferTimer = 0
end
e.stickLastAngle = rawAngle
e.lastIntendedMag = m.intendedMag
end
function wario_before_phys_step(m)
local hScale = 1.0
-- slower on ground
if (m.action & ACT_FLAG_MOVING) ~= 0 then
hScale = hScale * 0.9
end
-- make wario sink
if (m.action & ACT_FLAG_SWIMMING) ~= 0 then
if m.action ~= ACT_WATER_PLUNGE then
m.vel.y = m.vel.y - 3
end
end
-- faster holding item
if m.heldObj ~= nil then
m.vel.y = m.vel.y - 1
hScale = hScale * 1.3
if (m.action & ACT_FLAG_AIR) ~= 0 then
hScale = hScale * 1.3
end
end
m.vel.x = m.vel.x * hScale
m.vel.z = m.vel.z * hScale
end
function wario_on_set_action(m)
local e = gStateExtras[m.playerIndex]
-- air dash
if m.action == ACT_MOVE_PUNCHING and m.prevAction == ACT_WARIO_DASH then
local actionTimer = m.actionTimer
set_mario_action(m, ACT_WARIO_AIR_DASH, 0)
m.actionTimer = actionTimer
m.vel.x = 0
m.vel.y = 0
m.vel.z = 0
return
end
-- slow down when dash/conk ends
if (m.prevAction == ACT_WARIO_DASH) or (m.prevAction == ACT_WARIO_AIR_DASH) or (m.prevAction == ACT_CORKSCREW_CONK) then
if m.action == ACT_CORKSCREW_CONK then
mario_set_forward_vel(m, 60)
m.vel.x = 0
m.vel.y = 70.0
m.vel.z = 0
elseif (m.action == ACT_SLIDE_KICK) then
mario_set_forward_vel(m, 70)
m.vel.x = 0
m.vel.y = 30.0
m.vel.z = 0
elseif m.forwardVel > 20 then
mario_set_forward_vel(m, 20)
end
end
-- when hitting a wall which dashing, have one more single frame of dash
if m.action == ACT_GROUND_BONK and m.prevAction == ACT_WARIO_DASH then
set_mario_action(m, ACT_WARIO_DASH, 99)
mario_set_forward_vel(m, 1)
m.vel.x = 0
m.vel.y = 0
m.vel.z = 0
end
-- more height on triple jump
if m.action == ACT_TRIPLE_JUMP or m.action == ACT_SPECIAL_TRIPLE_JUMP then
m.vel.y = m.vel.y * 1.15
end
-- less height on other jumps
if m.action == ACT_JUMP or m.action == ACT_DOUBLE_JUMP or m.action == ACT_STEEP_JUMP or m.action == ACT_RIDING_SHELL_JUMP or m.action == ACT_BACKFLIP or m.action == ACT_LONG_JUMP then
m.vel.y = m.vel.y * 0.8
-- prevent from getting stuck on platform
if m.marioObj.platform ~= nil then
m.pos.y = m.pos.y + 10
end
elseif m.action == ACT_SIDE_FLIP then
m.vel.y = m.vel.y * 0.86
-- prevent from getting stuck on platform
if m.marioObj.platform ~= nil then
m.pos.y = m.pos.y + 10
end
end
e.lastAction = action
end
function wario_update(m)
local hScale = 1.0
local e = gStateExtras[m.playerIndex]
wario_update_spin_input(m)
-- spin around objects
if m.action == ACT_HOLD_IDLE or m.action == ACT_HOLD_WALKING then
if e.spinInput ~= 0 then
m.twirlYaw = m.intendedYaw
if e.spinDirection == 1 then
m.angleVel.y = 1500
else
m.angleVel.y = -1500
end
m.intendedMag = 21
return set_mario_action(m, ACT_WARIO_SPINNING_OBJ, 1)
end
end
-- turn heavy objects into light
if m.action == ACT_HOLD_HEAVY_IDLE then
return set_mario_action(m, ACT_HOLD_IDLE, 0)
end
-- turn dive into dash
if m.action == ACT_DIVE and m.prevAction == ACT_WALKING then
if (m.controller.buttonPressed & B_BUTTON) ~= 0 then
m.actionTimer = 0
return set_mario_action(m, ACT_WARIO_DASH, 0)
end
end
-- shake cmaera
if m.action == ACT_GROUND_POUND_LAND then
set_camera_shake_from_hit(SHAKE_MED_DAMAGE)
end
-- faster ground pound
if m.action == ACT_GROUND_POUND then
m.vel.y = m.vel.y * 1.3
end
-- more gravity
if (m.action & ACT_FLAG_AIR) ~= 0 then
m.vel.y = m.vel.y - 1.15
end
-- takes less damage
if m.action ~= ACT_LAVA_BOOST then
m.hurtCounter = m.hurtCounter * 0.5
end
m.vel.x = m.vel.x * hScale
m.vel.z = m.vel.z * hScale
e.prevPos.x = m.pos.x
e.prevPos.y = m.pos.y
e.prevPos.z = m.pos.z
end
gEventTable[CT_WARIO] = {
before_phys_step = wario_before_phys_step,
on_set_action = wario_on_set_action,
update = wario_update,
}
---------- ----------
-- main -- -- main --
---------- ----------
@ -462,9 +910,10 @@ function mario_before_phys_step(m)
return return
end end
if gEventTable[m.character.type] == nil then if gEventTable[m.character.type] == nil or gEventTable[m.character.type].before_phys_step == nil then
return return
end end
gEventTable[m.character.type].before_phys_step(m) gEventTable[m.character.type].before_phys_step(m)
end end
@ -473,20 +922,34 @@ function mario_on_set_action(m)
return return
end end
if gEventTable[m.character.type] == nil then if gEventTable[m.character.type] == nil or gEventTable[m.character.type].on_set_action == nil then
return return
end end
gEventTable[m.character.type].on_set_action(m) gEventTable[m.character.type].on_set_action(m)
end end
function mario_before_update(m)
if m.action == ACT_BUBBLED then
return
end
if gEventTable[m.character.type] == nil or gEventTable[m.character.type].before_update == nil then
return
end
gEventTable[m.character.type].before_update(m)
end
function mario_update(m) function mario_update(m)
if m.action == ACT_BUBBLED then if m.action == ACT_BUBBLED then
return return
end end
if gEventTable[m.character.type] == nil then if gEventTable[m.character.type] == nil or gEventTable[m.character.type].update == nil then
return return
end end
gEventTable[m.character.type].update(m) gEventTable[m.character.type].update(m)
end end
@ -494,10 +957,15 @@ end
-- hooks -- -- hooks --
----------- -----------
hook_event(HOOK_BEFORE_MARIO_UPDATE, mario_before_update)
hook_event(HOOK_MARIO_UPDATE, mario_update) hook_event(HOOK_MARIO_UPDATE, mario_update)
hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action) hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action)
hook_event(HOOK_BEFORE_PHYS_STEP, mario_before_phys_step) hook_event(HOOK_BEFORE_PHYS_STEP, mario_before_phys_step)
hook_mario_action(ACT_WALL_SLIDE, act_wall_slide) hook_mario_action(ACT_WALL_SLIDE, act_wall_slide)
hook_mario_action(ACT_SPIN_POUND, act_spin_pound) 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) 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)

View file

@ -29,14 +29,16 @@
#include "pc/network/network.h" #include "pc/network/network.h"
#include "pc/lua/smlua_hooks.h" #include "pc/lua/smlua_hooks.h"
#define INT_GROUND_POUND_OR_TWIRL (1 << 0) // 0x01 enum InteractionFlag {
#define INT_PUNCH (1 << 1) // 0x02 INT_GROUND_POUND_OR_TWIRL = (1 << 0), // 0x01
#define INT_KICK (1 << 2) // 0x04 INT_PUNCH = (1 << 1), // 0x02
#define INT_TRIP (1 << 3) // 0x08 INT_KICK = (1 << 2), // 0x04
#define INT_SLIDE_KICK (1 << 4) // 0x10 INT_TRIP = (1 << 3), // 0x08
#define INT_FAST_ATTACK_OR_SHELL (1 << 5) // 0x20 INT_SLIDE_KICK = (1 << 4), // 0x10
#define INT_HIT_FROM_ABOVE (1 << 6) // 0x40 INT_FAST_ATTACK_OR_SHELL = (1 << 5), // 0x20
#define INT_HIT_FROM_BELOW (1 << 7) // 0x80 INT_HIT_FROM_ABOVE = (1 << 6), // 0x40
INT_HIT_FROM_BELOW = (1 << 7), // 0x80
};
#define INT_ATTACK_NOT_FROM_BELOW \ #define INT_ATTACK_NOT_FROM_BELOW \
(INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \ (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK \
@ -192,15 +194,17 @@ u32 determine_interaction(struct MarioState *m, struct Object *o) {
u32 interaction = 0; u32 interaction = 0;
u32 action = m->action; u32 action = m->action;
interaction = smlua_get_action_interaction_type(m);
// hack: make water punch actually do something // hack: make water punch actually do something
if (m->action == ACT_WATER_PUNCH && o->oInteractType & INTERACT_PLAYER) { if (interaction == 0 && m->action == ACT_WATER_PUNCH && o->oInteractType & INTERACT_PLAYER) {
s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1]; s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1];
if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) { if (-0x2AAA <= dYawToObject && dYawToObject <= 0x2AAA) {
return INT_PUNCH; interaction = INT_PUNCH;
} }
} }
if (action & ACT_FLAG_ATTACKING) { if (interaction == 0 && action & ACT_FLAG_ATTACKING) {
if (action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) { if (action == ACT_PUNCHING || action == ACT_MOVE_PUNCHING || action == ACT_JUMP_KICK) {
s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1]; s16 dYawToObject = mario_obj_angle_to_object(m, o) - m->faceAngle[1];
@ -1347,6 +1351,7 @@ u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object
u8 isAttackerInvulnerable = (m->action & ACT_FLAG_INVULNERABLE) || m->invincTimer != 0 || m->hurtCounter != 0; u8 isAttackerInvulnerable = (m->action & ACT_FLAG_INVULNERABLE) || m->invincTimer != 0 || m->hurtCounter != 0;
u8 isInvulnerable = (m2->action & ACT_FLAG_INVULNERABLE) || m2->invincTimer != 0 || m2->hurtCounter != 0 || isInCutscene; u8 isInvulnerable = (m2->action & ACT_FLAG_INVULNERABLE) || m2->invincTimer != 0 || m2->hurtCounter != 0 || isInCutscene;
u8 isIgnoredAttack = (m->action == ACT_JUMP || m->action == ACT_DOUBLE_JUMP); u8 isIgnoredAttack = (m->action == ACT_JUMP || m->action == ACT_DOUBLE_JUMP);
if ((interaction & INT_ANY_ATTACK) && !(interaction & INT_HIT_FROM_ABOVE) && !isInvulnerable && !isIgnoredAttack && !isAttackerInvulnerable) { if ((interaction & INT_ANY_ATTACK) && !(interaction & INT_HIT_FROM_ABOVE) && !isInvulnerable && !isIgnoredAttack && !isAttackerInvulnerable) {
// determine if slide attack should be ignored // determine if slide attack should be ignored

View file

@ -115,6 +115,20 @@ char gSmluaConstants[] = ""
" end\n" " end\n"
" return current;\n" " return current;\n"
"end\n" "end\n"
"function approach_s32(current, target, inc, dec)\n"
" if current < target then\n"
" current = current + inc\n"
" if current > target then\n"
" current = target\n"
" end\n"
" else\n"
" current = current - dec\n"
" if current < target then\n"
" current = target\n"
" end\n"
" end\n"
" return current;\n"
"end\n"
"function SOUND_ARG_LOAD(bank, playFlags, soundID, priority, flags2)\n" "function SOUND_ARG_LOAD(bank, playFlags, soundID, priority, flags2)\n"
" return ((bank << 28) | (playFlags << 24) | (soundID << 16) | (priority << 8) | (flags2 << 4) | 1)\n" " return ((bank << 28) | (playFlags << 24) | (soundID << 16) | (priority << 8) | (flags2 << 4) | 1)\n"
"end\n" "end\n"
@ -818,6 +832,18 @@ char gSmluaConstants[] = ""
"CHAR_SOUND_SO_LONGA_BOWSER = 40\n" "CHAR_SOUND_SO_LONGA_BOWSER = 40\n"
"CHAR_SOUND_IMA_TIRED = 41\n" "CHAR_SOUND_IMA_TIRED = 41\n"
"CHAR_SOUND_MAX = 42\n" "CHAR_SOUND_MAX = 42\n"
"INT_GROUND_POUND_OR_TWIRL = (1 << 0)\n"
"INT_PUNCH = (1 << 1)\n"
"INT_KICK = (1 << 2)\n"
"INT_TRIP = (1 << 3)\n"
"INT_SLIDE_KICK = (1 << 4)\n"
"INT_FAST_ATTACK_OR_SHELL = (1 << 5)\n"
"INT_HIT_FROM_ABOVE = (1 << 6)\n"
"INT_HIT_FROM_BELOW = (1 << 7)\n"
"INT_ATTACK_NOT_FROM_BELOW = (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK | INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE)\n"
"INT_ANY_ATTACK = (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_SLIDE_KICK | INT_FAST_ATTACK_OR_SHELL | INT_HIT_FROM_ABOVE | INT_HIT_FROM_BELOW)\n"
"INT_ATTACK_NOT_WEAK_FROM_ABOVE = (INT_GROUND_POUND_OR_TWIRL | INT_PUNCH | INT_KICK | INT_TRIP | INT_HIT_FROM_BELOW)\n"
"INT_ATTACK_SLIDE = (INT_SLIDE_KICK | INT_FAST_ATTACK_OR_SHELL)\n"
"MARIO_ANIM_SLOW_LEDGE_GRAB = 0\n" "MARIO_ANIM_SLOW_LEDGE_GRAB = 0\n"
"MARIO_ANIM_FALL_OVER_BACKWARDS = 1\n" "MARIO_ANIM_FALL_OVER_BACKWARDS = 1\n"
"MARIO_ANIM_BACKWARD_AIR_KB = 2\n" "MARIO_ANIM_BACKWARD_AIR_KB = 2\n"

View file

@ -19,6 +19,16 @@ bool smlua_functions_valid_param_count(lua_State* L, int expected) {
return true; return true;
} }
bool smlua_functions_valid_param_range(lua_State* L, int min, int max) {
int top = lua_gettop(L);
if (top < min || top > max) {
LOG_LUA("improper param count: expected (%u - %u), received %u", min, max, top);
smlua_logline();
return false;
}
return true;
}
////////// //////////
// misc // // misc //
////////// //////////

View file

@ -2,6 +2,7 @@
#define SMLUA_FUNCTIONS_H #define SMLUA_FUNCTIONS_H
bool smlua_functions_valid_param_count(lua_State* L, int expected); bool smlua_functions_valid_param_count(lua_State* L, int expected);
bool smlua_functions_valid_param_range(lua_State* L, int min, int max);
void smlua_bind_functions(void); void smlua_bind_functions(void);
#endif #endif

View file

@ -12,6 +12,8 @@ static struct LuaHookedEvent sHookedEvents[HOOK_MAX] = { 0 };
int smlua_hook_event(lua_State* L) { int smlua_hook_event(lua_State* L) {
if (L == NULL) { return 0; } if (L == NULL) { return 0; }
if (!smlua_functions_valid_param_count(L, 2)) { return 0; }
u16 hookType = smlua_to_integer(L, -2); u16 hookType = smlua_to_integer(L, -2);
if (!gSmLuaConvertSuccess) { return 0; } if (!gSmLuaConvertSuccess) { return 0; }
@ -139,6 +141,7 @@ void smlua_call_event_hooks_network_player_param(enum LuaHookedEventType hookTyp
struct LuaHookedMarioAction { struct LuaHookedMarioAction {
u32 action; u32 action;
u32 interactionType;
int reference; int reference;
}; };
@ -149,6 +152,9 @@ static int sHookedMarioActionsCount = 0;
int smlua_hook_mario_action(lua_State* L) { int smlua_hook_mario_action(lua_State* L) {
if (L == NULL) { return 0; } if (L == NULL) { return 0; }
if (!smlua_functions_valid_param_range(L, 2, 3)) { return 0; }
int paramCount = lua_gettop(L);
if (sHookedMarioActionsCount >= MAX_HOOKED_ACTIONS) { if (sHookedMarioActionsCount >= MAX_HOOKED_ACTIONS) {
LOG_LUA("Hooked mario actions exceeded maximum references!"); LOG_LUA("Hooked mario actions exceeded maximum references!");
smlua_logline(); smlua_logline();
@ -162,6 +168,7 @@ int smlua_hook_mario_action(lua_State* L) {
return 0; return 0;
} }
lua_pushvalue(L, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX); int ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (ref == -1) { if (ref == -1) {
@ -170,8 +177,19 @@ int smlua_hook_mario_action(lua_State* L) {
return 0; return 0;
} }
lua_Integer interactionType = 0;
if (paramCount >= 3) {
interactionType = smlua_to_integer(L, 3);
if (interactionType == 0 || !gSmLuaConvertSuccess) {
LOG_LUA("Hook Action: tried to hook invalid interactionType: %lld, %u", interactionType, gSmLuaConvertSuccess);
smlua_logline();
return 0;
}
}
struct LuaHookedMarioAction* hooked = &sHookedMarioActions[sHookedMarioActionsCount]; struct LuaHookedMarioAction* hooked = &sHookedMarioActions[sHookedMarioActionsCount];
hooked->action = action; hooked->action = action;
hooked->interactionType = interactionType;
hooked->reference = ref; hooked->reference = ref;
if (!gSmLuaConvertSuccess) { return 0; } if (!gSmLuaConvertSuccess) { return 0; }
@ -213,6 +231,18 @@ bool smlua_call_action_hook(struct MarioState* m, s32* returnValue) {
return false; return false;
} }
u32 smlua_get_action_interaction_type(struct MarioState* m) {
u32 interactionType = 0;
lua_State* L = gLuaState;
if (L == NULL) { return false; }
for (int i = 0; i < sHookedMarioActionsCount; i++) {
if (sHookedMarioActions[i].action == m->action) {
interactionType |= sHookedMarioActions[i].interactionType;
}
}
return interactionType;
}
///////////////////////// /////////////////////////
// hooked chat command // // hooked chat command //
///////////////////////// /////////////////////////
@ -230,6 +260,8 @@ static int sHookedChatCommandsCount = 0;
int smlua_hook_chat_command(lua_State* L) { int smlua_hook_chat_command(lua_State* L) {
if (L == NULL) { return 0; } if (L == NULL) { return 0; }
if (!smlua_functions_valid_param_count(L, 3)) { return 0; }
if (sHookedChatCommandsCount >= MAX_HOOKED_CHAT_COMMANDS) { if (sHookedChatCommandsCount >= MAX_HOOKED_CHAT_COMMANDS) {
LOG_LUA("Hooked chat command exceeded maximum references!"); LOG_LUA("Hooked chat command exceeded maximum references!");
smlua_logline(); smlua_logline();

View file

@ -32,6 +32,7 @@ void smlua_call_event_hooks_mario_param(enum LuaHookedEventType hookType, struct
void smlua_call_event_hooks_mario_params(enum LuaHookedEventType hookType, struct MarioState* m1, struct MarioState* m2); void smlua_call_event_hooks_mario_params(enum LuaHookedEventType hookType, struct MarioState* m1, struct MarioState* m2);
bool smlua_call_action_hook(struct MarioState* m, s32* returnValue); bool smlua_call_action_hook(struct MarioState* m, s32* returnValue);
u32 smlua_get_action_interaction_type(struct MarioState* m);
bool smlua_call_chat_command_hook(char* command); bool smlua_call_chat_command_hook(char* command);
void smlua_display_chat_commands(void); void smlua_display_chat_commands(void);