sm64-roblox-liberty-prime/client/Mario/Airborne/init.server.lua
2023-07-17 19:19:03 -05:00

1302 lines
32 KiB
Lua

--!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 AirStep = Enums.AirStep
local MarioEyes = Enums.MarioEyes
local InputFlags = Enums.InputFlags
local MarioFlags = Enums.MarioFlags
local ParticleFlags = Enums.ParticleFlags
type Mario = System.Mario
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Helpers
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local function stopRising(m: Mario)
if m.Velocity.Y > 0 then
m.Velocity *= Vector3.new(1, 0, 1)
end
end
local function playFlipSounds(m: Mario, frame1: number, frame2: number, frame3: number)
local animFrame = m.AnimFrame
if animFrame == frame1 or animFrame == frame2 or animFrame == frame3 then
m:PlaySound(Sounds.ACTION_SPIN)
end
end
local function playKnockbackSound(m: Mario)
if m.ActionArg == 0 and math.abs(m.ForwardVel) >= 28 then
m:PlaySoundIfNoFlag(Sounds.MARIO_DOH, MarioFlags.MARIO_SOUND_PLAYED)
else
m:PlaySoundIfNoFlag(Sounds.MARIO_UH, MarioFlags.MARIO_SOUND_PLAYED)
end
end
local function lavaBoostOnWall(m: Mario)
local wall = m.Wall
if wall then
local angle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
m.FaceAngle = Util.SetY(m.FaceAngle, angle)
end
if m.ForwardVel < 24 then
m.ForwardVel = 24
end
if not m.Flags:Has(MarioFlags.METAL_CAP) then
m.HurtCounter += if m.Flags:Has(MarioFlags.CAP_ON_HEAD) then 12 else 18
end
m:PlaySound(Sounds.MARIO_ON_FIRE)
m:SetAction(Action.LAVA_BOOST, 1)
end
local function checkFallDamage(m: Mario, hardFallAction: number): boolean
local fallHeight = m.PeakHeight - m.Position.Y
local damageHeight = 1150
if m.Action() == Action.TWIRLING then
return false
end
if m.Velocity.Y < -55 and fallHeight > 3000 then
m.HurtCounter += if m.Flags:Has(MarioFlags.CAP_ON_HEAD) then 16 else 24
m:PlaySound(Sounds.MARIO_ATTACKED)
m:SetAction(hardFallAction, 4)
elseif fallHeight > damageHeight and not m:FloorIsSlippery() then
m.HurtCounter += if m.Flags:Has(MarioFlags.CAP_ON_HEAD) then 8 else 12
m:PlaySound(Sounds.MARIO_ATTACKED)
m.SquishTimer = 30
end
return false
end
local function checkKickOrDiveInAir(m: Mario): boolean
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(if m.ForwardVel > 28 then Action.DIVE else Action.JUMP_KICK)
end
return false
end
local function updateAirWithTurn(m: Mario)
local dragThreshold = if m.Action() == Action.LONG_JUMP then 48 else 32
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 0.35)
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
local intendedDYaw = m.IntendedYaw - m.FaceAngle.Y
local intendedMag = m.IntendedMag / 32
m.ForwardVel += 1.5 * Util.Coss(intendedDYaw) * intendedMag
m.FaceAngle += Vector3int16.new(0, 512 * Util.Sins(intendedDYaw) * intendedMag, 0)
end
if m.ForwardVel > dragThreshold then
m.ForwardVel -= 1
end
if m.ForwardVel < -16 then
m.ForwardVel += 2
end
m.SlideVelX = m.ForwardVel * Util.Sins(m.FaceAngle.Y)
m.SlideVelZ = m.ForwardVel * Util.Coss(m.FaceAngle.Y)
m.Velocity = Vector3.new(m.SlideVelX, m.Velocity.Y, m.SlideVelZ)
end
local function updateAirWithoutTurn(m: Mario)
local dragThreshold = 32
if m.Action() == Action.LONG_JUMP then
dragThreshold = 48
end
local sidewaysSpeed = 0
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 0.35)
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
local intendedDYaw = m.IntendedYaw - m.FaceAngle.Y
local intendedMag = m.IntendedMag / 32
m.ForwardVel += intendedMag * Util.Coss(intendedDYaw) * 1.5
sidewaysSpeed = intendedMag * Util.Sins(intendedDYaw) * 10
end
--! Uncapped air speed. Net positive when moving forward.
if m.ForwardVel > dragThreshold then
m.ForwardVel -= 1
end
if m.ForwardVel < -16 then
m.ForwardVel += 2
end
m.SlideVelX = m.ForwardVel * Util.Sins(m.FaceAngle.Y)
m.SlideVelZ = m.ForwardVel * Util.Coss(m.FaceAngle.Y)
m.SlideVelX += sidewaysSpeed * Util.Sins(m.FaceAngle.Y + 0x4000)
m.SlideVelZ += sidewaysSpeed * Util.Coss(m.FaceAngle.Y + 0x4000)
m.Velocity = Vector3.new(m.SlideVelX, m.Velocity.Y, m.SlideVelZ)
end
local function updateLavaBoostOrTwirling(m: Mario)
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
local intendedDYaw = m.IntendedYaw - m.FaceAngle.Y
local intendedMag = m.IntendedMag / 32
m.ForwardVel += Util.Coss(intendedDYaw) * intendedMag
m.FaceAngle += Vector3int16.new(0, Util.Sins(intendedDYaw) * intendedMag * 1024, 0)
if m.ForwardVel < 0 then
m.FaceAngle += Vector3int16.new(0, 0x8000, 0)
m.ForwardVel *= -1
end
if m.ForwardVel > 32 then
m.ForwardVel -= 2
end
end
m.SlideVelX = m.ForwardVel * Util.Sins(m.FaceAngle.Y)
m.SlideVelZ = m.ForwardVel * Util.Coss(m.FaceAngle.Y)
m.Velocity = Vector3.new(m.SlideVelX, m.Velocity.Y, m.SlideVelZ)
end
local function updateFlyingYaw(m: Mario)
local targetYawVel = -Util.SignedShort(m.Controller.StickX * (m.ForwardVel / 4))
if targetYawVel > 0 then
if m.AngleVel.Y < 0 then
m.AngleVel += Vector3int16.new(0, 0x40, 0)
if m.AngleVel.Y > 0x10 then
m.AngleVel = Util.SetY(m.AngleVel, 0x10)
end
else
local y = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x10, 0x20)
m.AngleVel = Util.SetY(m.AngleVel, y)
end
elseif targetYawVel < 0 then
if m.AngleVel.Y > 0 then
m.AngleVel -= Vector3int16.new(0, 0x40, 0)
if m.AngleVel.Y < -0x10 then
m.AngleVel = Util.SetY(m.AngleVel, -0x10)
end
else
local y = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x20, 0x10)
m.AngleVel = Util.SetY(m.AngleVel, y)
end
else
local y = Util.ApproachInt(m.AngleVel.Y, 0, 0x40)
m.AngleVel = Util.SetY(m.AngleVel, y)
end
m.FaceAngle += Vector3int16.new(0, m.AngleVel.Y, 0)
m.FaceAngle = Util.SetZ(m.FaceAngle, 20 * -m.AngleVel.Y)
end
local function updateFlyingPitch(m: Mario)
local targetPitchVel = -Util.SignedShort(m.Controller.StickY * (m.ForwardVel / 5))
if targetPitchVel > 0 then
if m.AngleVel.X < 0 then
m.AngleVel += Vector3int16.new(0x40, 0, 0)
if m.AngleVel.X > 0x20 then
m.AngleVel = Util.SetX(m.AngleVel, 0x20)
end
else
local x = Util.ApproachInt(m.AngleVel.X, targetPitchVel, 0x20, 0x40)
m.AngleVel = Util.SetX(m.AngleVel, x)
end
elseif targetPitchVel < 0 then
if m.AngleVel.X > 0 then
m.AngleVel -= Vector3int16.new(0x40, 0, 0)
if m.AngleVel.X < -0x20 then
m.AngleVel = Util.SetX(m.AngleVel, -0x20)
end
else
local x = Util.ApproachInt(m.AngleVel.X, targetPitchVel, 0x40, 0x20)
m.AngleVel = Util.SetX(m.AngleVel, x)
end
else
local x = Util.ApproachInt(m.AngleVel.X, 0, 0x40)
m.AngleVel = Util.SetX(m.AngleVel, x)
end
end
local function updateFlying(m: Mario)
updateFlyingPitch(m)
updateFlyingYaw(m)
m.ForwardVel -= 2 * (m.FaceAngle.X / 0x4000) + 0.1
m.ForwardVel -= 0.5 * (1 - Util.Coss(m.AngleVel.Y))
if m.ForwardVel < 0 then
m.ForwardVel = 0
end
if m.ForwardVel > 16 then
m.FaceAngle += Vector3int16.new((m.ForwardVel - 32) * 6, 0, 0)
elseif m.ForwardVel > 4 then
m.FaceAngle += Vector3int16.new((m.ForwardVel - 32) * 10, 0, 0)
else
m.FaceAngle -= Vector3int16.new(0x400, 0, 0)
end
m.FaceAngle += Vector3int16.new(m.AngleVel.X, 0, 0)
if m.FaceAngle.X > 0x2AAA then
m.FaceAngle = Util.SetX(m.FaceAngle, 0x2AAA)
end
if m.FaceAngle.X < -0x2AAA then
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
end
local velX = Util.Coss(m.FaceAngle.X) * Util.Sins(m.FaceAngle.Y)
m.SlideVelX = m.ForwardVel * velX
local velZ = Util.Coss(m.FaceAngle.X) * Util.Coss(m.FaceAngle.Y)
m.SlideVelZ = m.ForwardVel * velZ
local velY = Util.Sins(m.FaceAngle.X)
m.Velocity = m.ForwardVel * Vector3.new(velX, velY, velZ)
end
local function commonAirActionStep(m: Mario, landAction: number, anim: Animation, stepArg: number): number
local stepResult
do
updateAirWithoutTurn(m)
stepResult = m:PerformAirStep(stepArg)
end
if stepResult == AirStep.NONE then
m:SetAnimation(anim)
elseif stepResult == AirStep.LANDED then
if not checkFallDamage(m, Action.HARD_BACKWARD_GROUND_KB) then
m:SetAction(landAction)
end
elseif stepResult == AirStep.HIT_WALL then
m:SetAnimation(anim)
if m.ForwardVel > 16 then
m:BonkReflection()
m.FaceAngle += Vector3int16.new(0, 0x8000, 0)
if m.Wall then
m:SetAction(Action.AIR_HIT_WALL)
else
stopRising(m)
if m.ForwardVel >= 38 then
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
else
if m.ForwardVel > 8 then
m:SetForwardVel(-8)
end
m:SetAction(Action.SOFT_BONK)
end
end
else
m:SetForwardVel(0)
end
elseif stepResult == AirStep.GRABBED_LEDGE then
m:SetAnimation(Animations.IDLE_ON_LEDGE)
m:SetAction(Action.LEDGE_GRAB)
elseif stepResult == AirStep.GRABBED_CEILING then
m:SetAction(Action.START_HANGING)
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return stepResult
end
local function commonRolloutStep(m: Mario, anim: Animation)
local stepResult
if m.ActionState == 0 then
m.Velocity = Util.SetY(m.Velocity, 30)
m.ActionState = 1
end
m:PlaySound(Sounds.ACTION_TERRAIN_JUMP)
updateAirWithoutTurn(m)
stepResult = m:PerformAirStep()
if stepResult == AirStep.NONE then
if m.ActionState == 1 then
if m:SetAnimation(anim) == 4 then
m:PlaySound(Sounds.ACTION_SPIN)
end
else
m:SetAnimation(Animations.GENERAL_FALL)
end
elseif stepResult == AirStep.LANDED then
m:SetAction(Action.FREEFALL_LAND_STOP)
m:PlayLandingSound()
elseif stepResult == AirStep.HIT_WALL then
m:SetForwardVel(0)
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
if m.ActionState == 1 and m:IsAnimPastEnd() then
m.ActionState = 2
end
end
local function commonAirKnockbackStep(
m: Mario,
landAction: number,
hardFallAction: number,
anim: Animation,
speed: number
)
local stepResult
do
m:SetForwardVel(speed)
stepResult = m:PerformAirStep()
end
if stepResult == AirStep.NONE then
m:SetAnimation(anim)
elseif stepResult == AirStep.LANDED then
if not checkFallDamage(m, hardFallAction) then
local action = m.Action()
if action == Action.THROWN_FORWARD or action == Action.THROWN_BACKWARD then
m:SetAction(landAction, m.HurtCounter)
else
m:SetAction(landAction, m.ActionArg)
end
end
elseif stepResult == AirStep.HIT_WALL then
m:SetAnimation(Animations.BACKWARD_AIR_KB)
m:BonkReflection()
stopRising(m)
m:SetForwardVel(-speed)
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return stepResult
end
local function checkWallKick(m: Mario)
if m.WallKickTimer ~= 0 then
if m.Input:Has(InputFlags.A_PRESSED) then
if m.PrevAction() == Action.AIR_HIT_WALL then
m.FaceAngle += Vector3int16.new(0, 0x8000, 0)
end
end
end
return false
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Actions
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local AIR_STEP_CHECK_BOTH = bit32.bor(AirStep.CHECK_LEDGE_GRAB, AirStep.CHECK_HANG)
local DEF_ACTION: (number, (Mario) -> boolean) -> () = System.RegisterAction
DEF_ACTION(Action.JUMP, function(m: Mario)
if checkKickOrDiveInAir(m) then
return true
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
commonAirActionStep(m, Action.JUMP_LAND, Animations.SINGLE_JUMP, AIR_STEP_CHECK_BOTH)
return false
end)
DEF_ACTION(Action.DOUBLE_JUMP, function(m: Mario)
local anim = if m.Velocity.Y >= 0 then Animations.DOUBLE_JUMP_RISE else Animations.DOUBLE_JUMP_FALL
if checkKickOrDiveInAir(m) then
return true
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP, Sounds.MARIO_HOOHOO)
commonAirActionStep(m, Action.DOUBLE_JUMP_LAND, anim, AIR_STEP_CHECK_BOTH)
return false
end)
DEF_ACTION(Action.TRIPLE_JUMP, function(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
commonAirActionStep(m, Action.TRIPLE_JUMP_LAND, Animations.TRIPLE_JUMP, 0)
playFlipSounds(m, 2, 8, 20)
return false
end)
DEF_ACTION(Action.BACKFLIP, function(m: Mario)
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP, Sounds.MARIO_YAH_WAH_HOO)
commonAirActionStep(m, Action.BACKFLIP_LAND, Animations.BACKFLIP, 0)
playFlipSounds(m, 2, 3, 17)
return false
end)
DEF_ACTION(Action.FREEFALL, function(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
local anim
if m.ActionArg == 0 then
anim = Animations.GENERAL_FALL
elseif m.ActionArg == 1 then
anim = Animations.FALL_FROM_SLIDE
elseif m.ActionArg == 2 then
anim = Animations.FALL_FROM_SLIDE_KICK
end
commonAirActionStep(m, Action.FREEFALL_LAND, anim, AirStep.CHECK_LEDGE_GRAB)
return false
end)
DEF_ACTION(Action.SIDE_FLIP, function(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE, 0)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
commonAirActionStep(m, Action.SIDE_FLIP_LAND, Animations.SLIDEFLIP, AirStep.CHECK_LEDGE_GRAB)
if m.AnimFrame == 6 then
m:PlaySound(Sounds.ACTION_SIDE_FLIP)
end
return false
end)
DEF_ACTION(Action.WALL_KICK_AIR, function(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayJumpSound()
commonAirActionStep(m, Action.JUMP_LAND, Animations.SLIDEJUMP, AirStep.CHECK_LEDGE_GRAB)
return false
end)
DEF_ACTION(Action.LONG_JUMP, function(m: Mario)
local anim = if m.LongJumpIsSlow then Animations.SLOW_LONGJUMP else Animations.FAST_LONGJUMP
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP, Sounds.MARIO_YAHOO)
commonAirActionStep(m, Action.LONG_JUMP_LAND, anim, AirStep.CHECK_LEDGE_GRAB)
return false
end)
DEF_ACTION(Action.TWIRLING, function(m: Mario)
local startTwirlYaw = m.TwirlYaw
local yawVelTarget = 0x1000
if m.Input:Has(InputFlags.A_DOWN) then
yawVelTarget = 0x2000
end
local yVel = Util.ApproachInt(m.AngleVel.Y, yawVelTarget, 0x200)
m.AngleVel = Util.SetY(m.AngleVel, yVel)
m.TwirlYaw += yVel
m:SetAnimation(if m.ActionArg == 0 then Animations.START_TWIRL else Animations.TWIRL)
if m:IsAnimPastEnd() then
m.ActionArg = 1
end
if startTwirlYaw > m.TwirlYaw then
m:PlaySound(Sounds.ACTION_TWIRL)
end
local step = m:PerformAirStep()
if step == AirStep.LANDED then
m:SetAction(Action.TWIRL_LAND)
elseif step == AirStep.HIT_WALL then
m:BonkReflection(false)
elseif step == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
m.GfxAngle += Vector3int16.new(0, m.TwirlYaw, 0)
return false
end)
DEF_ACTION(Action.DIVE, function(m: Mario)
local airStep
if m.ActionArg == 0 then
m:PlayMarioSound(Sounds.ACTION_THROW, Sounds.MARIO_HOOHOO)
else
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
end
m:SetAnimation(Animations.DIVE)
updateAirWithoutTurn(m)
airStep = m:PerformAirStep()
if airStep == AirStep.NONE then
if m.Velocity.Y < 0 and m.FaceAngle.X > -0x2AAA then
m.FaceAngle -= Vector3int16.new(0x200, 0, 0)
if m.FaceAngle.X < -0x2AAA then
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
end
end
m.GfxAngle = Util.SetX(m.GfxAngle, -m.FaceAngle.X)
elseif airStep == AirStep.LANDED then
if not checkFallDamage(m, Action.HARD_FORWARD_GROUND_KB) then
m:SetAction(Action.DIVE_SLIDE)
end
m.FaceAngle *= Vector3int16.new(0, 1, 1)
elseif airStep == AirStep.HIT_WALL then
m:BonkReflection(true)
m.FaceAngle *= Vector3int16.new(0, 1, 1)
stopRising(m)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
elseif airStep == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return false
end)
DEF_ACTION(Action.WATER_JUMP, function(m: Mario)
if m.ForwardVel < 15 then
m:SetForwardVel(15)
end
m:PlaySound(Sounds.ACTION_WATER_EXIT)
m:SetAnimation(Animations.SINGLE_JUMP)
local step = m:PerformAirStep(AirStep.CHECK_LEDGE_GRAB)
if step == AirStep.LANDED then
m:SetAction(Action.JUMP_LAND)
elseif step == AirStep.HIT_WALL then
m:SetForwardVel(15)
elseif step == AirStep.GRABBED_LEDGE then
m:SetAnimation(Animations.IDLE_ON_LEDGE)
m:SetAction(Action.LEDGE_GRAB)
elseif step == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return false
end)
DEF_ACTION(Action.STEEP_JUMP, function(m: Mario)
local airStep
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
m:SetForwardVel(0.98 * m.ForwardVel)
airStep = m:PerformAirStep()
if airStep == AirStep.LANDED then
if not checkFallDamage(m, Action.HARD_BACKWARD_GROUND_KB) then
m.FaceAngle *= Vector3int16.new(0, 1, 1)
m:SetAction(if m.ForwardVel < 0 then Action.BEGIN_SLIDING else Action.JUMP_LAND)
end
elseif airStep == AirStep.HIT_WALL then
m:SetForwardVel(0)
elseif airStep == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
m:SetAnimation(Animations.SINGLE_JUMP)
m.GfxAngle = Util.SetY(m.GfxAngle, m.SteepJumpYaw)
return false
end)
DEF_ACTION(Action.GROUND_POUND, function(m: Mario)
local stepResult
local yOffset
m:PlaySoundIfNoFlag(Sounds.ACTION_THROW, MarioFlags.ACTION_SOUND_PLAYED)
if m.ActionState == 0 then
if m.ActionTimer < 10 then
yOffset = 20 - 2 * m.ActionTimer
if m.Position.Y + yOffset + 160 < m.CeilHeight then
m.Position += Vector3.new(0, yOffset, 0)
m.PeakHeight = m.Position.Y
end
end
m.Velocity = Util.SetY(m.Velocity, -50)
m:SetForwardVel(0)
m:SetAnimation(if m.ActionArg == 0 then Animations.START_GROUND_POUND else Animations.TRIPLE_JUMP_GROUND_POUND)
if m.ActionTimer == 0 then
m:PlaySound(Sounds.ACTION_SPIN)
end
m.ActionTimer += 1
m.GfxAngle = Vector3int16.new(0, m.FaceAngle.Y, 0)
if m.ActionTimer >= m.AnimFrameCount + 4 then
m:PlaySound(Sounds.MARIO_GROUND_POUND_WAH)
m.ActionState = 1
end
else
m:SetAnimation(Animations.GROUND_POUND)
stepResult = m:PerformAirStep()
if stepResult == AirStep.LANDED then
m:PlayHeavyLandingSound(Sounds.ACTION_HEAVY_LANDING)
if not checkFallDamage(m, Action.HARD_BACKWARD_GROUND_KB) then
m.ParticleFlags:Add(ParticleFlags.MIST_CIRCLE, ParticleFlags.HORIZONTAL_STAR)
m:SetAction(Action.GROUND_POUND_LAND)
end
elseif stepResult == AirStep.HIT_WALL then
m:SetForwardVel(-16)
stopRising(m)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
end
end
return false
end)
DEF_ACTION(Action.BURNING_JUMP, function(m: Mario)
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP)
m:SetForwardVel(m.ForwardVel)
if m:PerformAirStep() == AirStep.LANDED then
m:PlayLandingSound()
m:SetAction(Action.BURNING_GROUND)
end
m:SetAnimation(Animations.GENERAL_FALL)
m.ParticleFlags:Add(ParticleFlags.FIRE)
m:PlaySound(Sounds.MOVING_LAVA_BURN)
m.BurnTimer += 3
m.Health -= 10
if m.Health < 0x100 then
m.Health = 0xFF
end
return false
end)
DEF_ACTION(Action.BURNING_FALL, function(m: Mario)
m:SetForwardVel(m.ForwardVel)
if m:PerformAirStep() == AirStep.LANDED then
m:PlayLandingSound(Sounds.ACTION_TERRAIN_LANDING)
m:SetAction(Action.BURNING_GROUND)
end
m:SetAnimation(Animations.GENERAL_FALL)
m.ParticleFlags:Add(ParticleFlags.FIRE)
m.BurnTimer += 3
m.Health -= 10
if m.Health < 0x100 then
m.Health = 0xFF
end
return false
end)
DEF_ACTION(Action.BACKWARD_AIR_KB, function(m: Mario)
if checkWallKick(m) then
return true
end
playKnockbackSound(m)
commonAirKnockbackStep(
m,
Action.BACKWARD_GROUND_KB,
Action.HARD_BACKWARD_GROUND_KB,
Animations.BACKWARD_AIR_KB,
-16
)
return false
end)
DEF_ACTION(Action.FORWARD_AIR_KB, function(m: Mario)
if checkWallKick(m) then
return true
end
playKnockbackSound(m)
commonAirKnockbackStep(m, Action.FORWARD_GROUND_KB, Action.HARD_FORWARD_GROUND_KB, Animations.FORWARD_AIR_KB, 16)
return false
end)
DEF_ACTION(Action.HARD_BACKWARD_AIR_KB, function(m: Mario)
if checkWallKick(m) then
return true
end
playKnockbackSound(m)
commonAirKnockbackStep(
m,
Action.HARD_BACKWARD_GROUND_KB,
Action.HARD_BACKWARD_GROUND_KB,
Animations.BACKWARD_AIR_KB,
-16
)
return false
end)
DEF_ACTION(Action.HARD_FORWARD_AIR_KB, function(m: Mario)
if checkWallKick(m) then
return true
end
playKnockbackSound(m)
commonAirKnockbackStep(
m,
Action.HARD_FORWARD_GROUND_KB,
Action.HARD_FORWARD_GROUND_KB,
Animations.FORWARD_AIR_KB,
16
)
return false
end)
DEF_ACTION(Action.THROWN_BACKWARD, function(m: Mario)
local landAction = if m.ActionArg ~= 0 then Action.HARD_BACKWARD_GROUND_KB else Action.BACKWARD_GROUND_KB
m:PlaySoundIfNoFlag(Sounds.MARIO_WAAAOOOW, MarioFlags.MARIO_SOUND_PLAYED)
commonAirKnockbackStep(m, landAction, Action.HARD_BACKWARD_GROUND_KB, Animations.BACKWARD_AIR_KB, m.ForwardVel)
m.ForwardVel *= 0.98
return false
end)
DEF_ACTION(Action.THROWN_FORWARD, function(m: Mario)
local landAction = if m.ActionArg ~= 0 then Action.HARD_FORWARD_GROUND_KB else Action.FORWARD_GROUND_KB
m:PlaySoundIfNoFlag(Sounds.MARIO_WAAAOOOW, MarioFlags.MARIO_SOUND_PLAYED)
if
commonAirKnockbackStep(m, landAction, Action.HARD_FORWARD_GROUND_KB, Animations.FORWARD_AIR_KB, m.ForwardVel)
== AirStep.NONE
then
local pitch = Util.Atan2s(m.ForwardVel, -m.Velocity.Y)
if pitch > 0x1800 then
pitch = 0x1800
end
m.GfxAngle = Util.SetX(m.GfxAngle, pitch + 0x1800)
end
m.ForwardVel *= 0.98
return false
end)
DEF_ACTION(Action.SOFT_BONK, function(m: Mario)
if checkWallKick(m) then
return true
end
playKnockbackSound(m)
commonAirKnockbackStep(
m,
Action.FREEFALL_LAND,
Action.HARD_BACKWARD_GROUND_KB,
Animations.GENERAL_FALL,
m.ForwardVel
)
return false
end)
DEF_ACTION(Action.AIR_HIT_WALL, function(m: Mario)
m.ActionTimer += 1
if m.ActionTimer <= 2 then
if m.Input:Has(InputFlags.A_PRESSED) then
m.Velocity = Util.SetY(m.Velocity, 52)
m.FaceAngle += Vector3int16.new(0, 0x8000, 0)
return m:SetAction(Action.WALL_KICK_AIR)
end
elseif m.ForwardVel >= 38 then
m.WallKickTimer = 5
if m.Velocity.Y > 0 then
m.Velocity = Util.SetY(m.Velocity, 0)
end
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
return m:SetAction(Action.BACKWARD_AIR_KB)
else
m.WallKickTimer = 5
if m.Velocity.Y > 0 then
m.Velocity = Util.SetY(m.Velocity, 0)
end
if m.ForwardVel > 8 then
m:SetForwardVel(-8)
end
return m:SetAction(Action.SOFT_BONK)
end
return m:SetAnimation(Animations.START_WALLKICK) > 0
end)
DEF_ACTION(Action.FORWARD_ROLLOUT, function(m: Mario)
commonRolloutStep(m, Animations.FORWARD_SPINNING)
return false
end)
DEF_ACTION(Action.BACKWARD_ROLLOUT, function(m: Mario)
commonRolloutStep(m, Animations.BACKWARD_SPINNING)
return false
end)
DEF_ACTION(Action.BUTT_SLIDE_AIR, function(m: Mario)
local stepResult
m.ActionTimer += 1
if m.ActionTimer > 30 and m.Position.Y - m.FloorHeight > 500 then
return m:SetAction(Action.FREEFALL, 1)
end
updateAirWithTurn(m)
stepResult = m:PerformAirStep()
if stepResult == AirStep.LANDED then
if m.ActionState == 0 and m.Velocity.Y < 0 then
local floor = m.Floor
if floor and floor.Normal.Y > 0.9848077 then
m.Velocity *= Vector3.new(1, -0.5, 1)
m.ActionState = 1
else
m:SetAction(Action.BUTT_SLIDE)
end
else
m:SetAction(Action.BUTT_SLIDE)
end
m:PlayLandingSound()
elseif stepResult == AirStep.HIT_WALL then
stopRising(m)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
m:SetAnimation(Animations.SLIDE)
return false
end)
DEF_ACTION(Action.LAVA_BOOST, function(m: Mario)
local stepResult
m:PlaySoundIfNoFlag(Sounds.MARIO_ON_FIRE, MarioFlags.MARIO_SOUND_PLAYED)
if not m.Input:Has(InputFlags.NONZERO_ANALOG) then
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 0.35)
end
updateLavaBoostOrTwirling(m)
stepResult = m:PerformAirStep()
if stepResult == AirStep.LANDED then
local floor = m.Floor
local floorType: Enum.Material?
if floor then
floorType = floor.Material
end
if floorType == Enum.Material.CrackedLava then
m.ActionState = 0
if not m.Flags:Has(MarioFlags.METAL_CAP) then
m.HurtCounter += if m.Flags:Has(MarioFlags.CAP_ON_HEAD) then 12 else 18
end
m.Velocity = Util.SetY(m.Velocity, 84)
m:PlaySound(Sounds.MARIO_ON_FIRE)
else
m:PlayHeavyLandingSound(Sounds.ACTION_TERRAIN_BODY_HIT_GROUND)
if m.ActionState < 2 and m.Velocity.Y < 0 then
m.Velocity *= Vector3.new(1, -0.4, 1)
m:SetForwardVel(m.ForwardVel / 2)
m.ActionState += 1
else
m:SetAction(Action.LAVA_BOOST_LAND)
end
end
elseif stepResult == AirStep.HIT_WALL then
m:BonkReflection()
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
m:SetAnimation(Animations.FIRE_LAVA_BURN)
if not m.Flags:Has(MarioFlags.METAL_CAP) and m.Velocity.Y > 0 then
m.ParticleFlags:Add(ParticleFlags.FIRE)
if m.ActionState == 0 then
m:PlaySound(Sounds.MOVING_LAVA_BURN)
end
end
m.BodyState.EyeState = MarioEyes.DEAD
return false
end)
DEF_ACTION(Action.SLIDE_KICK, function(m: Mario)
local stepResult
if m.ActionState == 0 and m.ActionTimer == 0 then
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP, Sounds.MARIO_HOOHOO)
m:SetAnimation(Animations.SLIDE_KICK)
end
m.ActionTimer += 1
if m.ActionTimer > 30 and m.Position.Y - m.FloorHeight > 500 then
return m:SetAction(Action.FREEFALL, 2)
end
updateAirWithoutTurn(m)
stepResult = m:PerformAirStep()
if stepResult == AirStep.NONE then
if m.ActionState == 0 then
local tilt = Util.Atan2s(m.ForwardVel, -m.Velocity.Y)
if tilt > 0x1800 then
tilt = 0x1800
end
m.GfxAngle = Util.SetX(m.GfxAngle, tilt)
end
elseif stepResult == AirStep.LANDED then
if m.ActionState == 0 and m.Velocity.Y < 0 then
m.Velocity *= Vector3.new(1, -0.5, 1)
m.ActionState = 1
m.ActionTimer = 0
else
m:SetAction(Action.SLIDE_KICK_SLIDE)
end
m:PlayLandingSound()
elseif stepResult == AirStep.HIT_WALL then
stopRising(m)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return false
end)
DEF_ACTION(Action.JUMP_KICK, function(m: Mario)
local stepResult
if m.ActionState == 0 then
m:PlaySoundIfNoFlag(Sounds.MARIO_PUNCH_HOO, MarioFlags.MARIO_SOUND_PLAYED)
m.AnimReset = true
m:SetAnimation(Animations.AIR_KICK)
m.ActionState = 1
end
local animFrame = m.AnimFrame
if animFrame == 0 then
m.BodyState.PunchType = 2
m.BodyState.PunchTimer = 6
end
if animFrame >= 0 and animFrame < 8 then
m.Flags:Add(MarioFlags.KICKING)
end
updateAirWithoutTurn(m)
stepResult = m:PerformAirStep()
if stepResult == AirStep.LANDED then
if not checkFallDamage(m, Action.HARD_BACKWARD_GROUND_KB) then
m:SetAction(Action.FREEFALL_LAND)
end
elseif stepResult == AirStep.HIT_WALL then
m:SetForwardVel(0)
end
return false
end)
DEF_ACTION(Action.FLYING, function(m: Mario)
local startPitch = m.FaceAngle.X
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
if not m.Flags:Has(MarioFlags.WING_CAP) then
return m:SetAction(Action.FREEFALL)
end
if m.ActionState == 0 then
if m.ActionArg == 0 then
m:SetAnimation(Animations.FLY_FROM_CANNON)
else
m:SetAnimation(Animations.FORWARD_SPINNING_FLIP)
if m.AnimFrame == 1 then
m:PlaySound(Sounds.ACTION_SPIN)
end
end
if m:IsAnimAtEnd() then
m:SetAnimation(Animations.WING_CAP_FLY)
m.ActionState = 1
end
end
local stepResult
do
updateFlying(m)
stepResult = m:PerformAirStep()
end
if stepResult == AirStep.NONE then
m.GfxAngle = Util.SetX(m.GfxAngle, -m.FaceAngle.X)
m.GfxAngle = Util.SetZ(m.GfxAngle, m.FaceAngle.Z)
m.ActionTimer = 0
elseif stepResult == AirStep.LANDED then
m:SetAction(Action.DIVE_SLIDE)
m:SetAnimation(Animations.DIVE)
m:SetAnimToFrame(7)
m.FaceAngle *= Vector3int16.new(0, 1, 1)
elseif stepResult == AirStep.HIT_WALL then
if m.Wall then
m:SetForwardVel(-16)
m.FaceAngle *= Vector3int16.new(0, 1, 1)
stopRising(m)
m:PlaySound(if m.Flags:Has(MarioFlags.METAL_CAP) then Sounds.ACTION_METAL_BONK else Sounds.ACTION_BONK)
m.ParticleFlags:Add(ParticleFlags.VERTICAL_STAR)
m:SetAction(Action.BACKWARD_AIR_KB)
else
m.ActionTimer += 1
if m.ActionTimer == 0 then
m:PlaySound(Sounds.ACTION_HIT)
end
if m.ActionTimer == 30 then
m.ActionTimer = 0
end
m.FaceAngle -= Vector3int16.new(0x200, 0, 0)
if m.FaceAngle.X < -0x2AAA then
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
end
m.GfxAngle = Util.SetX(m.GfxAngle, -m.FaceAngle.X)
m.GfxAngle = Util.SetZ(m.GfxAngle, m.FaceAngle.Z)
end
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
if m.FaceAngle.X > 0x800 and m.ForwardVel >= 48 then
m.ParticleFlags:Add(ParticleFlags.DUST)
end
if startPitch <= 0 and m.FaceAngle.X > 0 and m.ForwardVel >= 48 then
m:PlaySound(Sounds.ACTION_FLYING_FAST)
m:PlaySound(Sounds.MARIO_YAHOO_WAHA_YIPPEE)
end
m:PlaySound(Sounds.MOVING_FLYING)
m:AdjustSoundForSpeed()
return false
end)
DEF_ACTION(Action.FLYING_TRIPLE_JUMP, function(m: Mario)
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.DIVE)
end
if m.Input:Has(InputFlags.Z_PRESSED) then
return m:SetAction(Action.GROUND_POUND)
end
m:PlayMarioSound(Sounds.ACTION_TERRAIN_JUMP, Sounds.MARIO_YAHOO)
if m.ActionState == 0 then
m:SetAnimation(Animations.TRIPLE_JUMP_FLY)
if m.AnimFrame == 7 then
m:PlaySound(Sounds.ACTION_SPIN)
end
if m:IsAnimPastEnd() then
m:SetAnimation(Animations.FORWARD_SPINNING)
m.ActionState = 1
end
end
if m.ActionState == 1 and m.AnimFrame == 1 then
m:PlaySound(Sounds.ACTION_SPIN)
end
if m.Velocity.Y < 4 then
if m.ForwardVel < 32 then
m:SetForwardVel(32)
end
m:SetAction(Action.FLYING, 1)
end
m.ActionTimer += 1
local stepResult
do
updateAirWithoutTurn(m)
stepResult = m:PerformAirStep()
end
if stepResult == AirStep.LANDED then
if not checkFallDamage(m, Action.HARD_BACKWARD_GROUND_KB) then
m:SetAction(Action.DOUBLE_JUMP_LAND)
end
elseif stepResult == AirStep.HIT_WALL then
m:BonkReflection()
elseif stepResult == AirStep.HIT_LAVA_WALL then
lavaBoostOnWall(m)
end
return false
end)
DEF_ACTION(Action.SPAWN_SPIN_AIRBORNE, function(m: Mario)
m:SetForwardVel(m.ForwardVel)
if m:PerformAirStep() == AirStep.LANDED then
m:PlayLandingSound(Sounds.ACTION_TERRAIN_LANDING)
m:SetAction(Action.SPAWN_SPIN_LANDING)
end
if m.ActionState == 0 and m.Position.Y - m.FloorHeight > 300 then
if m:SetAnimation(Animations.FORWARD_SPINNING) == 0 then
m:PlaySound(Sounds.ACTION_SPIN)
end
else
m.ActionState = 1
m:SetAnimation(Animations.GENERAL_FALL)
end
return false
end)
DEF_ACTION(Action.SPAWN_SPIN_LANDING, function(m: Mario)
m:StopAndSetHeightToFloor()
m:SetAnimation(Animations.GENERAL_LAND)
if m:IsAnimAtEnd() then
m:SetAction(Action.IDLE)
end
return false
end)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------