sm64-roblox-liberty-prime/client/Mario/Moving/init.server.lua

1496 lines
36 KiB
Lua
Raw Normal View History

--!strict
local System = require(script.Parent)
local Animations = System.Animations
local Sounds = System.Sounds
local Enums = System.Enums
local Util = System.Util
local Action = Enums.Action
local ActionFlags = Enums.ActionFlags
local ActionGroup = Enums.ActionGroups
local MarioEyes = Enums.MarioEyes
local GroundStep = Enums.GroundStep
local InputFlags = Enums.InputFlags
local MarioFlags = Enums.MarioFlags
local SurfaceClass = Enums.SurfaceClass
local ParticleFlags = Enums.ParticleFlags
type Mario = System.Mario
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Landing Actions
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
type LandingAction = {
NumFrames: number,
JumpTimer: number,
EndAction: number,
APressedAction: number,
}
local sJumpLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 5,
EndAction = Action.JUMP_LAND_STOP,
APressedAction = Action.DOUBLE_JUMP,
}
local sFreefallLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 5,
EndAction = Action.FREEFALL_LAND_STOP,
APressedAction = Action.DOUBLE_JUMP,
}
local sSideFlipLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 5,
EndAction = Action.SIDE_FLIP_LAND_STOP,
APressedAction = Action.DOUBLE_JUMP,
}
local sLongJumpLandAction: LandingAction = {
NumFrames = 6,
JumpTimer = 5,
EndAction = Action.LONG_JUMP_LAND_STOP,
APressedAction = Action.LONG_JUMP,
}
local sDoubleJumpLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 5,
EndAction = Action.DOUBLE_JUMP_LAND_STOP,
APressedAction = Action.JUMP,
}
local sTripleJumpLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 0,
EndAction = Action.TRIPLE_JUMP_LAND_STOP,
APressedAction = Action.UNINITIALIZED,
}
local sBackflipLandAction: LandingAction = {
NumFrames = 4,
JumpTimer = 0,
EndAction = Action.BACKFLIP_LAND_STOP,
APressedAction = Action.BACKFLIP,
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Helpers
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local DEF_ACTION: (number, (Mario) -> boolean) -> () = System.RegisterAction
local sPunchingForwardVelocities = { 0, 1, 1, 2, 3, 5, 7, 10 }
local function tiltBodyRunning(m: Mario)
local pitch = m:FindFloorSlope(0)
pitch = pitch * m.ForwardVel / 40
return -pitch
end
local function playStepSound(m: Mario, frame1: number, frame2: number)
if m:IsAnimPastFrame(frame1) or m:IsAnimPastFrame(frame2) then
if m.Flags:Has(MarioFlags.METAL_CAP) then
m:PlaySoundAndSpawnParticles(Sounds.ACTION_METAL_STEP, 0)
else
m:PlaySoundAndSpawnParticles(Sounds.ACTION_TERRAIN_STEP, 0)
end
end
end
local function alignWithFloor(m: Mario)
local pos = Util.SetY(m.Position, m.FloorHeight)
m.Position = pos
local radius = 40
local minY = -radius * 3
local yaw = m.FaceAngle.Y
local p0_x = pos.X + radius * Util.Sins(yaw + 0x2AAA)
local p0_z = pos.Z + radius * Util.Coss(yaw + 0x2AAA)
local p1_x = pos.X + radius * Util.Sins(yaw + 0x8000)
local p1_z = pos.Z + radius * Util.Coss(yaw + 0x8000)
local p2_x = pos.X + radius * Util.Sins(yaw + 0xD555)
local p2_z = pos.Z + radius * Util.Coss(yaw + 0xD555)
local test0 = Vector3.new(p0_x, pos.Y + 150, p0_z)
local test1 = Vector3.new(p1_x, pos.Y + 150, p1_z)
local test2 = Vector3.new(p2_x, pos.Y + 150, p2_z)
local p0_y = Util.FindFloor(test0)
local p1_y = Util.FindFloor(test1)
local p2_y = Util.FindFloor(test2)
p0_y = p0_y - pos.Y < minY and pos.Y or p0_y
p1_y = p1_y - pos.Y < minY and pos.Y or p1_y
p2_y = p2_y - pos.Y < minY and pos.Y or p2_y
local avgY = (p0_y + p1_y + p2_y) / 3
local forward = Vector3.new(Util.Sins(yaw), 0, Util.Coss(yaw))
if avgY >= pos.Y then
pos = Util.SetY(pos, avgY)
end
local a = Vector3.new(p0_x, p0_y, p0_z)
local b = Vector3.new(p1_x, p1_y, p1_z)
local c = Vector3.new(p2_x, p2_y, p2_z)
local yColumn = (b - a):Cross(c - a).Unit
local xColumn = yColumn:Cross(forward).Unit
m.ThrowMatrix = CFrame.fromMatrix(pos, xColumn, yColumn)
end
local function beginWalkingAction(m: Mario, forwardVel: number, action: number, actionArg: number?)
m:SetForwardVel(forwardVel)
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, m.IntendedYaw)
return m:SetAction(action, actionArg)
end
local function checkLedgeClimbDown(m: Mario)
if m.ForwardVel < 10 then
local pos, wall = Util.FindWallCollisions(m.Position, -10, 10)
if wall then
local floorHeight, floor = Util.FindFloor(pos)
if floor and pos.Y - floorHeight > 160 then
local wallAngle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
local wallDYaw = wallAngle - m.FaceAngle.Y
if math.abs(wallDYaw) < 0x4000 then
pos -= Vector3.new(20 * wall.Normal.X, 0, 20 * wall.Normal.Z)
m.Position = pos
m.FaceAngle *= Vector3int16.new(0, 1, 1)
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, wallAngle + 0x8000)
m:SetAction(Action.LEDGE_CLIMB_DOWN)
m:SetAnimation(Animations.CLIMB_DOWN_LEDGE)
end
end
end
end
end
local function slideBonk(m: Mario, fastAction: number, slowAction: number)
if m.ForwardVel > 16 then
m:BonkReflection(true)
m:SetAction(fastAction)
else
m:SetForwardVel(0)
m:SetAction(slowAction)
end
end
local function setTripleJumpAction(m: Mario)
if m.Flags:Has(MarioFlags.WING_CAP) then
return m:SetAction(Action.FLYING_TRIPLE_JUMP)
elseif m.ForwardVel > 20 then
return m:SetAction(Action.TRIPLE_JUMP)
else
return m:SetAction(Action.JUMP)
end
end
local function updateSlidingAngle(m: Mario, accel: number, lossFactor: number)
local newFacingDYaw
local facingDYaw
local floor = m.Floor
if not floor then
return
end
assert(floor)
local slopeAngle = Util.Atan2s(floor.Normal.Z, floor.Normal.X)
local steepness = math.sqrt(floor.Normal.X ^ 2 + floor.Normal.Z ^ 2)
m.SlideVelX += accel * steepness * Util.Sins(slopeAngle)
m.SlideVelZ += accel * steepness * Util.Coss(slopeAngle)
m.SlideVelX *= lossFactor
m.SlideVelZ *= lossFactor
m.SlideYaw = Util.Atan2s(m.SlideVelZ, m.SlideVelX)
facingDYaw = Util.SignedShort(m.FaceAngle.Y - m.SlideYaw)
newFacingDYaw = facingDYaw
if newFacingDYaw > 0 and newFacingDYaw <= 0x4000 then
newFacingDYaw -= 0x200
if newFacingDYaw < 0 then
newFacingDYaw = 0
end
elseif newFacingDYaw > -0x4000 and newFacingDYaw < 0 then
newFacingDYaw += 0x200
if newFacingDYaw > 0 then
newFacingDYaw = 0
end
elseif newFacingDYaw > 0x4000 and newFacingDYaw < 0x8000 then
newFacingDYaw += 0x200
if newFacingDYaw > 0x8000 then
newFacingDYaw = 0x8000
end
elseif newFacingDYaw > -0x8000 and newFacingDYaw < -0x4000 then
newFacingDYaw -= 0x200
if newFacingDYaw < -0x8000 then
newFacingDYaw = -0x8000
end
end
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, m.SlideYaw + newFacingDYaw)
m.Velocity = Vector3.new(m.SlideVelX, 0, m.SlideVelZ)
--! Speed is capped a frame late (butt slide HSG)
m.ForwardVel = math.sqrt(m.SlideVelX ^ 2 + m.SlideVelZ ^ 2)
if m.ForwardVel > 100 then
m.SlideVelX = m.SlideVelX * 100 / m.ForwardVel
m.SlideVelZ = m.SlideVelZ * 100 / m.ForwardVel
end
if math.abs(newFacingDYaw) > 0x4000 then
m.ForwardVel *= -1
end
end
local function updateSliding(m: Mario, stopSpeed: number)
local intendedDYaw = Util.SignedShort(m.IntendedYaw - m.SlideYaw)
local forward = Util.Coss(intendedDYaw)
local sideward = Util.Sins(intendedDYaw)
--! 10k glitch
if forward < 0 and m.ForwardVel > 0 then
forward *= 0.5 + 0.5 * m.ForwardVel / 100
end
local floorClass = m:GetFloorClass()
local lossFactor
local accel
if floorClass == SurfaceClass.VERY_SLIPPERY then
accel = 10
lossFactor = m.IntendedMag / 32 * forward * 0.02 + 0.98
elseif floorClass == SurfaceClass.SLIPPERY then
accel = 8
lossFactor = m.IntendedMag / 32 * forward * 0.02 + 0.96
elseif floorClass == SurfaceClass.DEFAULT then
accel = 7
lossFactor = m.IntendedMag / 32 * forward * 0.02 + 0.92
elseif floorClass == SurfaceClass.NOT_SLIPPERY then
accel = 5
lossFactor = m.IntendedMag / 32 * forward * 0.02 + 0.92
end
local oldSpeed = math.sqrt(m.SlideVelX ^ 2 + m.SlideVelZ ^ 2)
--! This is attempting to use trig derivatives to rotate Mario's speed.
-- It is slightly off/asymmetric since it uses the new X speed, but the old
-- Z speed.
m.SlideVelX += m.SlideVelZ * (m.IntendedMag / 32) * sideward * 0.05
m.SlideVelZ -= m.SlideVelX * (m.IntendedMag / 32) * sideward * 0.05
local newSpeed = math.sqrt(m.SlideVelX ^ 2 + m.SlideVelZ ^ 2)
if oldSpeed > 0 and newSpeed > 0 then
m.SlideVelX *= oldSpeed / newSpeed
m.SlideVelZ *= oldSpeed / newSpeed
end
local stopped = false
updateSlidingAngle(m, accel, lossFactor)
if not m:FloorIsSlope() and m.ForwardVel ^ 2 < stopSpeed ^ 2 then
m:SetForwardVel(0)
stopped = true
end
return stopped
end
local function applySlopeAccel(m: Mario)
local floor = m.Floor
local floorNormal: Vector3
if floor then
floorNormal = floor.Normal
else
floorNormal = Vector3.yAxis
end
local floorDYaw = m.FloorAngle - m.FaceAngle.Y
local steepness = math.sqrt(floorNormal.X ^ 2 + floorNormal.Z ^ 2)
if m:FloorIsSlope() then
local slopeClass = 0
local slopeAccel
if m.Action() ~= Action.SOFT_BACKWARD_GROUND_KB then
if m.Action() ~= Action.SOFT_FORWARD_GROUND_KB then
slopeClass = m:GetFloorClass()
end
end
if slopeClass == SurfaceClass.VERY_SLIPPERY then
slopeAccel = 5.3
elseif slopeClass == SurfaceClass.SLIPPERY then
slopeAccel = 2.7
elseif slopeClass == SurfaceClass.DEFAULT then
slopeAccel = 1.7
else
slopeAccel = 0
end
if floorDYaw > -0x4000 and floorDYaw < 0x4000 then
m.ForwardVel += slopeAccel * steepness
else
m.ForwardVel -= slopeAccel * steepness
end
end
m.SlideYaw = m.FaceAngle.Y
m.SlideVelX = m.ForwardVel * Util.Sins(m.FaceAngle.Y)
m.SlideVelZ = m.ForwardVel * Util.Coss(m.FaceAngle.Y)
m.Velocity = Vector3.new(m.SlideVelX, 0, m.SlideVelZ)
end
local function applyLandingAccel(m: Mario, frictionFactor: number)
local stopped = false
applySlopeAccel(m)
if not m:FloorIsSlope() then
m.ForwardVel *= frictionFactor
if m.ForwardVel ^ 2 < 1 then
m:SetForwardVel(0)
stopped = true
end
end
return stopped
end
local function applySlopeDecel(m: Mario, decelCoef: number)
local decel
local stopped = false
local floorClass = m:GetFloorClass()
if floorClass == SurfaceClass.VERY_SLIPPERY then
decel = decelCoef * 0.2
elseif floorClass == SurfaceClass.SLIPPERY then
decel = decelCoef * 0.7
elseif floorClass == SurfaceClass.DEFAULT then
decel = decelCoef * 2
elseif floorClass == SurfaceClass.NOT_SLIPPERY then
decel = decelCoef * 3
end
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, decel)
if m.ForwardVel == 0 then
stopped = true
end
applySlopeAccel(m)
return stopped
end
local function updateDeceleratingSpeed(m: Mario)
local stopped = false
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 1)
if m.ForwardVel == 0 then
stopped = true
end
m:SetForwardVel(m.ForwardVel)
return stopped
end
local function updateWalkingSpeed(m: Mario)
local maxTargetSpeed = 32
local floor = m.Floor
local targetSpeed = if m.IntendedMag < maxTargetSpeed then m.IntendedMag else maxTargetSpeed
if m.ForwardVel < 0 then
m.ForwardVel += 1.1
elseif m.ForwardVel <= targetSpeed then
m.ForwardVel += 1.1 - m.ForwardVel / 43
elseif floor and floor.Normal.Y >= 0.95 then
m.ForwardVel -= 1
end
if m.ForwardVel > 48 then
m.ForwardVel = 48
end
local currY = Util.SignedShort(m.IntendedYaw - m.FaceAngle.Y)
local faceY = m.IntendedYaw - Util.ApproachInt(currY, 0, 0x800)
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, faceY)
applySlopeAccel(m)
end
local function shouldBeginSliding(m: Mario)
if m.Input:Has(InputFlags.ABOVE_SLIDE) then
if m.ForwardVel < -1 or m:FacingDownhill() then
return true
end
end
return false
end
local function analogStickHeldBack(m: Mario)
local intendedDYaw = Util.SignedShort(m.IntendedYaw - m.FaceAngle.Y)
return math.abs(intendedDYaw) > 0x471C
end
local function checkGroundDiveOrPunch(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
--! Speed kick (shoutouts to SimpleFlips)
if m.ForwardVel >= 29 and m.Controller.StickMag > 48 then
m.Velocity = Util.SetY(m.Velocity, 20)
return m:SetAction(Action.DIVE, 1)
end
return m:SetAction(Action.MOVE_PUNCHING)
end
return false
end
local function beginBrakingAction(m: Mario)
if m.ActionState == 1 then
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, m.ActionArg)
return m:SetAction(Action.STANDING_AGAINST_WALL)
end
if m.ForwardVel > 16 then
local floor = m.Floor
if floor and floor.Normal.Y >= 0.17364818 then
return m:SetAction(Action.BRAKING)
end
end
return m:SetAction(Action.DECELERATING)
end
local function animAndAudioForWalk(m: Mario)
local baseAccel = if m.IntendedMag > m.ForwardVel then m.IntendedMag else m.ForwardVel
if baseAccel < 4 then
baseAccel = 4
end
local targetPitch = 0
local accel
while true do
if m.ActionTimer == 0 then
if baseAccel > 8 then
m.ActionTimer = 2
else
accel = baseAccel / 4 * 0x10000
if accel < 0x1000 then
accel = 0x1000
end
m:SetAnimationWithAccel(Animations.START_TIPTOE, accel)
playStepSound(m, 7, 22)
if m:IsAnimPastFrame(23) then
m.ActionTimer = 2
end
break
end
elseif m.ActionTimer == 1 then
if baseAccel > 8 then
m.ActionTimer = 2
else
accel = baseAccel * 0x10000
if accel < 0x1000 then
accel = 0x1000
end
m:SetAnimationWithAccel(Animations.TIPTOE, accel)
playStepSound(m, 14, 72)
break
end
elseif m.ActionTimer == 2 then
if baseAccel < 5 then
m.ActionTimer = 1
elseif baseAccel > 22 then
m.ActionTimer = 3
else
accel = baseAccel / 4 * 0x10000
m:SetAnimationWithAccel(Animations.WALKING, accel)
playStepSound(m, 10, 49)
break
end
elseif m.ActionTimer == 3 then
if baseAccel < 18 then
m.ActionTimer = 2
else
accel = baseAccel / 4 * 0x10000
m:SetAnimationWithAccel(Animations.RUNNING, accel)
playStepSound(m, 9, 45)
targetPitch = tiltBodyRunning(m)
break
end
end
end
local walkingPitch = Util.ApproachInt(m.WalkingPitch, targetPitch, 0x800)
walkingPitch = Util.SignedShort(walkingPitch)
m.WalkingPitch = walkingPitch
2023-07-18 00:19:03 +00:00
m.GfxAngle = Util.SetX(m.GfxAngle, walkingPitch)
end
local function pushOrSidleWall(m: Mario, startPos: Vector3)
local wallAngle: number
local dWallAngle: number
local dx = m.Position.X - startPos.X
local dz = m.Position.Z - startPos.Z
local movedDist = math.sqrt(dx ^ 2 + dz ^ 2)
local accel = movedDist * 2 * 0x10000
if m.ForwardVel > 6 then
m:SetForwardVel(6)
end
local wall = m.Wall
if wall then
wallAngle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
dWallAngle = Util.SignedShort(assert(wallAngle) - m.FaceAngle.Y)
end
if wall == nil or math.abs(dWallAngle) >= 0x71C8 then
m:SetAnimation(Animations.PUSHING)
playStepSound(m, 6, 18)
else
if dWallAngle < 0 then
m:SetAnimationWithAccel(Animations.SIDESTEP_RIGHT, accel)
else
m:SetAnimationWithAccel(Animations.SIDESTEP_LEFT, accel)
end
if m.AnimFrame < 20 then
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m.ParticleFlags:Add(ParticleFlags.DUST)
end
m.ActionState = 1
m.ActionArg = Util.SignedShort(wallAngle + 0x8000)
2023-07-18 00:19:03 +00:00
m.GfxAngle = Util.SetY(m.GfxAngle, m.ActionArg)
m.GfxAngle = Util.SetZ(m.GfxAngle, m:FindFloorSlope(0x4000))
end
end
local function tiltBodyWalking(m: Mario, startYaw: number)
local anim = m.AnimCurrent
local bodyState = m.BodyState
if anim == Animations.WALKING or anim == Animations.RUNNING then
local dYaw = m.FaceAngle.Y - startYaw
local tiltZ = -math.clamp(dYaw * m.ForwardVel / 12, -0x1555, 0x1555)
local tiltX = math.clamp(m.ForwardVel * 170, 0, 0x1555)
local torsoAngle = bodyState.TorsoAngle
tiltZ = Util.ApproachInt(torsoAngle.Z, tiltZ, 0x400)
tiltX = Util.ApproachInt(torsoAngle.X, tiltX, 0x400)
bodyState.TorsoAngle = Vector3int16.new(tiltX, torsoAngle.Y, tiltZ)
else
bodyState.TorsoAngle *= Vector3int16.new(0, 1, 0)
end
end
local function tiltBodyButtSlide(m: Mario)
local intendedDYaw = m.IntendedYaw - m.FaceAngle.Y
local bodyState = m.BodyState
local tiltX = 5461.3335 * m.IntendedMag / 32 * Util.Coss(intendedDYaw)
local tiltZ = -(5461.3335 * m.IntendedMag / 32 * Util.Sins(intendedDYaw))
local torsoAngle = bodyState.TorsoAngle
bodyState.TorsoAngle = Vector3int16.new(tiltX, torsoAngle.Y, tiltZ)
end
local function commonSlideAction(m: Mario, endAction: number, airAction: number, anim: Animation)
local pos = m.Position
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m:AdjustSoundForSpeed()
local step = m:PerformGroundStep()
if step == GroundStep.LEFT_GROUND then
m:SetAction(airAction)
if math.abs(m.ForwardVel) >= 50 then
m:PlaySound(Sounds.MARIO_HOOHOO)
end
elseif step == GroundStep.NONE then
m:SetAnimation(anim)
alignWithFloor(m)
m.ParticleFlags:Add(ParticleFlags.DUST)
elseif step == GroundStep.HIT_WALL then
local wall = m.Wall
if not m:FloorIsSlippery() then
if m.ForwardVel > 16 then
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
end
slideBonk(m, Action.GROUND_BONK, endAction)
elseif wall then
local wallAngle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
local slideSpeed = math.sqrt(m.SlideVelX ^ 2 + m.SlideVelZ ^ 2) * 0.9
if slideSpeed < 4 then
slideSpeed = 4
end
local slideYaw = Util.SignedShort(m.SlideYaw - wallAngle)
m.SlideYaw = Util.SignedShort(wallAngle - slideYaw + 0x8000)
m.SlideVelX = slideSpeed * Util.Sins(m.SlideYaw)
m.SlideVelZ = slideSpeed * Util.Coss(m.SlideYaw)
m.Velocity = Vector3.new(m.SlideVelX, m.Velocity.Y, m.SlideVelZ)
end
alignWithFloor(m)
end
end
local function commonSlideActionWithJump(m: Mario, stopAction: number, airAction: number, anim: Animation)
if m.ActionTimer == 5 then
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetJumpingAction(Action.JUMP)
end
else
m.ActionTimer += 1
end
if updateSliding(m, 4) then
m:SetAction(stopAction)
end
commonSlideAction(m, stopAction, airAction, anim)
return false
end
local function commonLandingCancels(
m: Mario,
landingAction: LandingAction,
setAPressAction: (Mario, number, any) -> any
)
local floor = m.Floor
if floor and floor.Normal.Y < 0.2923717 then
return m:PushOffSteepFloor(Action.FREEFALL)
end
m.DoubleJumpTimer = landingAction.JumpTimer
if shouldBeginSliding(m) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.FIRST_PERSON) then
return m:SetAction(landingAction.EndAction)
end
m.ActionTimer += 1
if m.ActionTimer >= landingAction.NumFrames then
return m:SetAction(landingAction.EndAction)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return setAPressAction(m, landingAction.APressedAction, 0)
end
if m.Input:Has(InputFlags.OFF_FLOOR) then
return m:SetAction(Action.FREEFALL)
end
return false
end
local function stomachSlideAction(m: Mario, stopAction: number, airAction: number, anim: Animation)
if m.ActionTimer == 5 then
if not m.Input:Has(InputFlags.ABOVE_SLIDE) and m.Input:Has(InputFlags.A_PRESSED, InputFlags.B_PRESSED) then
return m:SetAction(if m.ForwardVel >= 0 then Action.FORWARD_ROLLOUT else Action.BACKWARD_ROLLOUT)
end
else
m.ActionTimer += 1
end
if updateSliding(m, 4) then
return m:SetAction(stopAction)
end
commonSlideAction(m, stopAction, airAction, anim)
return false
end
local function commonGroundKnockbackAction(
m: Mario,
anim: Animation,
minFrame: number,
playHeavyLanding: boolean,
attacked: number
)
local animFrame
if playHeavyLanding then
m:PlayHeavyLandingSoundOnce(Sounds.ACTION_TERRAIN_BODY_HIT_GROUND)
end
if attacked > 0 then
m:PlaySoundIfNoFlag(Sounds.MARIO_ATTACKED, MarioFlags.MARIO_SOUND_PLAYED)
else
m:PlaySoundIfNoFlag(Sounds.MARIO_OOOF, MarioFlags.MARIO_SOUND_PLAYED)
end
m.ForwardVel = math.clamp(m.ForwardVel, -32, 32)
animFrame = m:SetAnimation(anim)
if animFrame < minFrame then
applyLandingAccel(m, 0.9)
elseif m.ForwardVel > 0 then
m:SetForwardVel(0.1)
else
m:SetForwardVel(-0.1)
end
if m:PerformGroundStep() == GroundStep.LEFT_GROUND then
if m.ForwardVel >= 0 then
m:SetAction(Action.FORWARD_AIR_KB, attacked)
else
m:SetAction(Action.BACKWARD_AIR_KB, attacked)
end
elseif m:IsAnimAtEnd() then
if m.Health < 0x100 then
m:SetAction(Action.STANDING_DEATH)
else
if attacked > 0 then
m.InvincTimer = 30
end
m:SetAction(Action.IDLE)
end
end
return animFrame
end
local function commonLandingAction(m: Mario, anim: Animation)
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
applyLandingAccel(m, 0.98)
elseif m.ForwardVel > 16 then
applySlopeDecel(m, 2)
else
m.Velocity *= Vector3.new(1, 0, 1)
end
local stepResult = m:PerformGroundStep()
if stepResult == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif stepResult == GroundStep.HIT_WALL then
m:SetAnimation(Animations.PUSHING)
end
if m.ForwardVel > 16 then
m.ParticleFlags:Add(ParticleFlags.DUST)
end
m:SetAnimation(anim)
m:PlayLandingSoundOnce(Sounds.ACTION_TERRAIN_LANDING)
return stepResult
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DEF_ACTION(Action.WALKING, function(m: Mario)
local startPos
local startYaw = m.FaceAngle.Y
if shouldBeginSliding(m) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.FIRST_PERSON) then
return beginBrakingAction(m)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetJumpFromLanding()
end
if checkGroundDiveOrPunch(m) then
return true
end
2023-07-18 00:19:03 +00:00
if m.Input:Has(InputFlags.NO_MOVEMENT) then
return beginBrakingAction(m)
end
if analogStickHeldBack(m) and m.ForwardVel >= 16 then
return m:SetAction(Action.TURNING_AROUND)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.CROUCH_SLIDE)
end
local step
do
m.ActionState = 0
startPos = m.Position
updateWalkingSpeed(m)
step = m:PerformGroundStep()
end
if step == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
m:SetAnimation(Animations.GENERAL_FALL)
elseif step == GroundStep.NONE then
animAndAudioForWalk(m)
if m.IntendedMag - m.ForwardVel > 16 then
m.ParticleFlags:Add(ParticleFlags.DUST)
end
elseif step == GroundStep.HIT_WALL then
pushOrSidleWall(m, startPos)
m.ActionTimer = 0
end
checkLedgeClimbDown(m)
tiltBodyWalking(m, startYaw)
return false
end)
DEF_ACTION(Action.MOVE_PUNCHING, function(m: Mario)
if shouldBeginSliding(m) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.ActionState == 0 and m.Input:Has(InputFlags.A_DOWN) then
return m:SetAction(Action.JUMP_KICK)
end
m.ActionState = 1
m:UpdatePunchSequence()
if m.ForwardVel > 0 then
applySlopeDecel(m, 0.5)
else
m.ForwardVel += 8
if m.ForwardVel >= 0 then
m.ForwardVel = 0
end
applySlopeAccel(m)
end
local step = m:PerformGroundStep()
if step == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif step == GroundStep.NONE then
m.ParticleFlags:Add(ParticleFlags.DUST)
end
return false
end)
DEF_ACTION(Action.TURNING_AROUND, function(m: Mario)
if m.Input:Has(InputFlags.ABOVE_SLIDE) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.SIDE_FLIP)
end
if not analogStickHeldBack(m) then
return m:SetAction(Action.WALKING)
end
if applySlopeDecel(m, 2) then
return beginWalkingAction(m, 8, Action.FINISH_TURNING_AROUND)
end
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m:AdjustSoundForSpeed()
local step = m:PerformGroundStep()
if step == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif step == GroundStep.NONE then
m.ParticleFlags:Add(ParticleFlags.DUST)
end
if m.ForwardVel >= 18 then
m:SetAnimation(Animations.TURNING_PART1)
else
m:SetAnimation(Animations.TURNING_PART2)
m.GfxAngle += Vector3int16.new(0, 0x8000, 0)
if m:IsAnimAtEnd() then
if m.ForwardVel > 0 then
beginWalkingAction(m, -m.ForwardVel, Action.WALKING)
else
beginWalkingAction(m, 8, Action.WALKING)
end
end
end
return false
end)
DEF_ACTION(Action.FINISH_TURNING_AROUND, function(m: Mario)
if m.Input:Has(InputFlags.ABOVE_SLIDE) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.SIDE_FLIP)
end
updateWalkingSpeed(m)
m:SetAnimation(Animations.TURNING_PART2)
if m:PerformGroundStep() == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
end
if m:IsAnimAtEnd() then
m:SetAction(Action.WALKING)
m.AnimSkipInterp = 2
end
return false
end)
DEF_ACTION(Action.BRAKING, function(m: Mario)
if not m.Input:Has(InputFlags.FIRST_PERSON) then
if
m.Input:Has(InputFlags.NONZERO_ANALOG, InputFlags.A_PRESSED, InputFlags.OFF_FLOOR, InputFlags.ABOVE_SLIDE)
then
return m:CheckCommonActionExits()
end
end
if applySlopeDecel(m, 2) then
return m:SetAction(Action.BRAKING_STOP)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.MOVE_PUNCHING)
end
local stepResult = m:PerformGroundStep()
if stepResult == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif stepResult == GroundStep.NONE then
m.ParticleFlags:Add(ParticleFlags.DUST)
elseif stepResult == GroundStep.HIT_WALL then
slideBonk(m, Action.BACKWARD_GROUND_KB, Action.BRAKING_STOP)
end
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m:SetAnimation(Animations.SKID_ON_GROUND)
m:AdjustSoundForSpeed()
return false
end)
DEF_ACTION(Action.DECELERATING, function(m: Mario)
if not m.Input:Has(InputFlags.FIRST_PERSON) then
if shouldBeginSliding(m) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetJumpFromLanding()
end
if checkGroundDiveOrPunch(m) then
return true
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
return m:SetAction(Action.WALKING)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.CROUCH_SLIDE)
end
end
if updateDeceleratingSpeed(m) then
return m:SetAction(Action.IDLE)
end
local slopeClass = m:GetFloorClass()
local stepResult = m:PerformGroundStep()
if stepResult == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif stepResult == GroundStep.HIT_WALL then
if slopeClass == SurfaceClass.VERY_SLIPPERY then
m:BonkReflection(true)
else
m:SetForwardVel(0)
end
end
if slopeClass == SurfaceClass.VERY_SLIPPERY then
m:SetAnimation(Animations.IDLE_HEAD_LEFT)
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m:AdjustSoundForSpeed()
m.ParticleFlags:Add(ParticleFlags.DUST)
else
local accel = m.ForwardVel / 4 * 0x10000
if accel < 0x1000 then
accel = 0x1000
end
m:SetAnimationWithAccel(Animations.WALKING, accel)
playStepSound(m, 10, 49)
end
return false
end)
DEF_ACTION(Action.CRAWLING, function(m: Mario)
if shouldBeginSliding(m) then
return m:SetAction(Action.BEGIN_SLIDING)
end
if m.Input:Has(InputFlags.FIRST_PERSON) then
return m:SetAction(Action.STOP_CRAWLING)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetJumpingAction(Action.JUMP)
end
if checkGroundDiveOrPunch(m) then
return true
end
2023-07-18 00:19:03 +00:00
if m.Input:Has(InputFlags.NO_MOVEMENT) then
return m:SetAction(Action.STOP_CRAWLING)
end
if not m.Input:Has(InputFlags.Z_DOWN) then
return m:SetAction(Action.STOP_CRAWLING)
end
m.IntendedMag *= 0.1
updateWalkingSpeed(m)
local stepResult = m:PerformGroundStep()
if stepResult == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL)
elseif stepResult == GroundStep.HIT_WALL then
if m.ForwardVel > 10 then
m:SetForwardVel(10)
end
alignWithFloor(m)
elseif stepResult == GroundStep.NONE then
alignWithFloor(m)
end
local accel = m.IntendedMag * 2 * 0x10000
m:SetAnimationWithAccel(Animations.CRAWLING, accel)
playStepSound(m, 26, 79)
return false
end)
DEF_ACTION(Action.BURNING_GROUND, function(m: Mario)
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.BURNING_JUMP)
end
m.BurnTimer += 2
if m.BurnTimer > 160 then
return m:SetAction(Action.WALKING)
end
if m.ForwardVel < 8 then
m.ForwardVel = 8
end
if m.ForwardVel > 48 then
m.ForwardVel = 48
end
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 32, 4, 1)
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
local faceY = m.IntendedYaw - Util.ApproachFloat(m.IntendedYaw - m.FaceAngle.Y, 0, 0x600)
2023-07-18 00:19:03 +00:00
m.FaceAngle = Util.SetY(m.FaceAngle, faceY)
end
applySlopeAccel(m)
if m:PerformGroundStep() == GroundStep.LEFT_GROUND then
m:SetAction(Action.BURNING_FALL)
end
local accel = m.ForwardVel / 2 * 0x10000
m:SetAnimationWithAccel(Animations.RUNNING, accel)
playStepSound(m, 9, 45)
m.ParticleFlags:Add(ParticleFlags.FIRE)
m:PlaySound(Sounds.MOVING_LAVA_BURN)
m.Health -= 10
if m.Health < 0x100 then
m:SetAction(Action.STANDING_DEATH)
end
m.BodyState.EyeState = MarioEyes.DEAD
return false
end)
DEF_ACTION(Action.BUTT_SLIDE, function(m: Mario)
local cancel = commonSlideActionWithJump(m, Action.BUTT_SLIDE_STOP, Action.BUTT_SLIDE_AIR, Animations.SLIDE)
tiltBodyButtSlide(m)
return cancel
end)
DEF_ACTION(Action.CROUCH_SLIDE, function(m: Mario)
if m.Input:Has(InputFlags.ABOVE_SLIDE) then
return m:SetAction(Action.BUTT_SLIDE)
end
if m.ActionTimer < 30 then
m.ActionTimer += 1
if m.Input:Has(InputFlags.A_PRESSED) then
if m.ForwardVel > 10 then
return m:SetJumpingAction(Action.LONG_JUMP)
end
end
end
if m.Input:Has(InputFlags.B_PRESSED) then
if m.ForwardVel >= 10 then
return m:SetAction(Action.SLIDE_KICK)
else
return m:SetAction(Action.MOVE_PUNCHING, 9)
end
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.JUMP)
end
if m.Input:Has(InputFlags.FIRST_PERSON) then
return m:SetAction(Action.BRAKING)
end
return commonSlideActionWithJump(m, Action.CROUCHING, Action.FREEFALL, Animations.START_CROUCHING)
end)
DEF_ACTION(Action.SLIDE_KICK_SLIDE, function(m: Mario)
local step
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.FORWARD_ROLLOUT)
end
m:SetAnimation(Animations.SLIDE_KICK)
if m:IsAnimAtEnd() and m.ForwardVel < 1 then
return m:SetAction(Action.SLIDE_KICK_SLIDE_STOP)
end
updateSliding(m, 1)
step = m:PerformGroundStep()
if step == GroundStep.LEFT_GROUND then
m:SetAction(Action.FREEFALL, 2)
elseif step == GroundStep.HIT_WALL then
m:BonkReflection(true)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_GROUND_KB)
end
m:PlaySound(Sounds.MOVING_TERRAIN_SLIDE)
m.ParticleFlags:Add(ParticleFlags.DUST)
return false
end)
DEF_ACTION(Action.STOMACH_SLIDE, function(m: Mario)
if m.ActionTimer == 5 then
if not m.Input:Has(InputFlags.ABOVE_SLIDE) and m.Input:Has(InputFlags.A_PRESSED, InputFlags.B_PRESSED) then
return m:SetAction(if m.ForwardVel >= 0 then Action.FORWARD_ROLLOUT else Action.BACKWARD_ROLLOUT)
end
else
m.ActionTimer += 1
end
if updateSliding(m, 4) then
return m:SetAction(Action.STOMACH_SLIDE_STOP)
end
commonSlideAction(m, Action.STOMACH_SLIDE_STOP, Action.FREEFALL, Animations.SLIDE_DIVE)
return false
end)
DEF_ACTION(Action.DIVE_SLIDE, function(m: Mario)
if not m.Input:Has(InputFlags.ABOVE_SLIDE) and m.Input:Has(InputFlags.A_PRESSED, InputFlags.B_PRESSED) then
return m:SetAction(if m.ForwardVel >= 0 then Action.FORWARD_ROLLOUT else Action.BACKWARD_ROLLOUT)
end
m:PlayLandingSoundOnce(Sounds.ACTION_TERRAIN_BODY_HIT_GROUND)
if updateSliding(m, 8) and m:IsAnimAtEnd() then
m:SetForwardVel(0)
m:SetAction(Action.STOMACH_SLIDE_STOP)
end
commonSlideAction(m, Action.STOMACH_SLIDE_STOP, Action.FREEFALL, Animations.DIVE)
return false
end)
DEF_ACTION(Action.HARD_BACKWARD_GROUND_KB, function(m: Mario)
local animFrame = commonGroundKnockbackAction(m, Animations.FALL_OVER_BACKWARDS, 43, true, m.ActionArg)
if animFrame == 43 and m.Health < 0x100 then
m:SetAction(Action.DEATH_ON_BACK)
end
if animFrame == 54 and m.PrevAction() == Action.SPECIAL_DEATH_EXIT then
m:PlaySound(Sounds.MARIO_MAMA_MIA)
end
if animFrame == 69 then
m:PlayLandingSoundOnce(Sounds.ACTION_TERRAIN_LANDING)
end
return false
end)
DEF_ACTION(Action.HARD_FORWARD_GROUND_KB, function(m: Mario)
local animFrame = commonGroundKnockbackAction(m, Animations.LAND_ON_STOMACH, 21, true, m.ActionArg)
if animFrame == 23 and m.Health < 0x100 then
m:SetAction(Action.DEATH_ON_STOMACH)
end
return false
end)
DEF_ACTION(Action.BACKWARD_GROUND_KB, function(m: Mario)
commonGroundKnockbackAction(m, Animations.BACKWARD_KB, 22, true, m.ActionArg)
return false
end)
DEF_ACTION(Action.FORWARD_GROUND_KB, function(m: Mario)
commonGroundKnockbackAction(m, Animations.FORWARD_KB, 20, true, m.ActionArg)
return false
end)
DEF_ACTION(Action.SOFT_BACKWARD_GROUND_KB, function(m: Mario)
commonGroundKnockbackAction(m, Animations.SOFT_BACK_KB, 100, false, m.ActionArg)
return false
end)
DEF_ACTION(Action.SOFT_FORWARD_GROUND_KB, function(m: Mario)
commonGroundKnockbackAction(m, Animations.SOFT_FRONT_KB, 100, false, m.ActionArg)
return false
end)
DEF_ACTION(Action.GROUND_BONK, function(m: Mario)
local animFrame = commonGroundKnockbackAction(m, Animations.GROUND_BONK, 32, true, m.ActionArg)
if animFrame == 32 then
m:PlayLandingSound(Sounds.ACTION_TERRAIN_LANDING)
end
return false
end)
DEF_ACTION(Action.JUMP_LAND, function(m: Mario)
if commonLandingCancels(m, sJumpLandAction, m.SetJumpingAction) then
return true
end
commonLandingAction(m, Animations.LAND_FROM_SINGLE_JUMP)
return false
end)
DEF_ACTION(Action.FREEFALL_LAND, function(m: Mario)
if commonLandingCancels(m, sFreefallLandAction, m.SetJumpingAction) then
return true
end
commonLandingAction(m, Animations.GENERAL_LAND)
return false
end)
DEF_ACTION(Action.SIDE_FLIP_LAND, function(m: Mario)
if commonLandingCancels(m, sSideFlipLandAction, m.SetJumpingAction) then
return true
end
if commonLandingAction(m, Animations.SLIDEFLIP_LAND) ~= GroundStep.HIT_WALL then
--m.GfxAngle += Vector3int16.new(0, 0x8000, 0)
end
return false
end)
DEF_ACTION(Action.LONG_JUMP_LAND, function(m: Mario)
if not m.Input:Has(InputFlags.Z_DOWN) then
m.Input:Remove(InputFlags.A_PRESSED)
end
if commonLandingCancels(m, sLongJumpLandAction, m.SetJumpingAction) then
return true
end
if not m.Input:Has(InputFlags.NONZERO_ANALOG) then
m:PlaySoundIfNoFlag(Sounds.MARIO_UH, MarioFlags.MARIO_SOUND_PLAYED)
end
commonLandingAction(
m,
if m.LongJumpIsSlow then Animations.CROUCH_FROM_FAST_LONGJUMP else Animations.CROUCH_FROM_SLOW_LONGJUMP
)
return false
end)
DEF_ACTION(Action.DOUBLE_JUMP_LAND, function(m: Mario)
if commonLandingCancels(m, sDoubleJumpLandAction, setTripleJumpAction) then
return true
end
commonLandingAction(m, Animations.LAND_FROM_DOUBLE_JUMP)
return false
end)
DEF_ACTION(Action.TRIPLE_JUMP_LAND, function(m: Mario)
m.Input:Remove(InputFlags.A_PRESSED)
if commonLandingCancels(m, sTripleJumpLandAction, m.SetJumpingAction) then
return true
end
if not m.Input:Has(InputFlags.NONZERO_ANALOG) then
m:PlaySoundIfNoFlag(Sounds.MARIO_HAHA, MarioFlags.MARIO_SOUND_PLAYED)
end
commonLandingAction(m, Animations.TRIPLE_JUMP_LAND)
return false
end)
DEF_ACTION(Action.BACKFLIP_LAND, function(m: Mario)
if not m.Input:Has(InputFlags.Z_DOWN) then
m.Input:Remove(InputFlags.A_PRESSED)
end
if commonLandingCancels(m, sBackflipLandAction, m.SetJumpingAction) then
return true
end
if not m.Input:Has(InputFlags.NONZERO_ANALOG) then
m:PlaySoundIfNoFlag(Sounds.MARIO_HAHA, MarioFlags.MARIO_SOUND_PLAYED)
end
commonLandingAction(m, Animations.TRIPLE_JUMP_LAND)
return false
end)
DEF_ACTION(Action.PUNCHING, function(m: Mario)
if m.Input:Has(InputFlags.STOMPED) then
return m:SetAction(Action.SHOCKWAVE_BOUNCE)
end
if m.Input:Has(InputFlags.NONZERO_ANALOG, InputFlags.A_PRESSED, InputFlags.OFF_FLOOR, InputFlags.ABOVE_SLIDE) then
return m:CheckCommonActionExits()
end
if m.ActionState and m.Input:Has(InputFlags.A_DOWN) then
return m:SetAction(Action.JUMP_KICK)
end
m.ActionState = 1
if m.ActionArg == 0 then
m.ActionTimer = 7
end
m:SetForwardVel(sPunchingForwardVelocities[m.ActionTimer + 1])
if m.ActionTimer > 0 then
m.ActionTimer -= 1
end
m:UpdatePunchSequence()
m:PerformGroundStep()
return false
end)