sm64-roblox-liberty-prime/client/Mario/Submerged/init.server.lua
2023-07-19 01:06:03 -05:00

857 lines
20 KiB
Lua

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 AirStep = Enums.AirStep
local WaterStep = Enums.WaterStep
local GroundStep = Enums.GroundStep
local InputFlags = Enums.InputFlags
local MarioFlags = Enums.MarioFlags
local ActionFlags = Enums.ActionFlags
local ParticleFlags = Enums.ParticleFlags
local MIN_SWIM_STRENGTH = 160
local MIN_SWIM_SPEED = 16
local sWasAtSurface = false
local sSwimStrength = MIN_SWIM_STRENGTH
local sBobTimer = 0
local sBobIncrement = 0
local sBobHeight = 0
type Mario = System.Mario
local function setSwimmingAtSurfaceParticles(m: Mario, particleFlag: number)
local atSurface = m.Position.Y >= m.WaterLevel - 130
if atSurface then
m.ParticleFlags:Add(particleFlag)
if atSurface ~= sWasAtSurface then
m:PlaySound(Sounds.ACTION_UNKNOWN431)
end
end
sWasAtSurface = atSurface
end
local function swimmingNearSurface(m: Mario)
if m.Flags:Has(MarioFlags.METAL_CAP) then
return false
end
return (m.WaterLevel - 80) - m.Position.Y < 400
end
local function getBuoyancy(m: Mario)
local buoyancy = 0
if m.Flags:Has(MarioFlags.METAL_CAP) then
if m.Action:Has(ActionFlags.INVULNERABLE) then
buoyancy = -2
else
buoyancy = -18
end
elseif swimmingNearSurface(m) then
buoyancy = 1.25
elseif not m.Action:Has(ActionFlags.MOVING) then
buoyancy = -2
end
return buoyancy
end
local function performWaterFullStep(m: Mario, nextPos: Vector3)
local adjusted, wall = Util.FindWallCollisions(nextPos, 10, 110)
nextPos = adjusted
local floorHeight, floor = Util.FindFloor(nextPos)
local ceilHeight = Util.FindCeil(nextPos, floorHeight)
if floor == nil then
return WaterStep.CANCELLED
end
if nextPos.Y >= floorHeight then
if ceilHeight - nextPos.Y >= 160 then
m.Position = nextPos
m.Floor = floor
m.FloorHeight = floorHeight
if wall then
return WaterStep.HIT_WALL
else
return WaterStep.NONE
end
end
if ceilHeight - floorHeight < 160 then
return WaterStep.CANCELLED
end
--! Water ceiling downwarp
m.Position = Util.SetY(nextPos, ceilHeight - 160)
m.Floor = floor
m.FloorHeight = floorHeight
return WaterStep.HIT_CEILING
else
if ceilHeight - floorHeight < 160 then
return WaterStep.CANCELLED
end
m.Position = Util.SetY(nextPos, floorHeight)
m.Floor = floor
m.FloorHeight = floorHeight
return WaterStep.HIT_FLOOR
end
end
local function applyWaterCurrent(m: Mario, step: Vector3): Vector3
-- TODO: Implement if actually needed.
-- This normally handles whirlpools and moving
-- water, neither of which I think I'll be using.
return step
end
local function performWaterStep(m: Mario)
local nextPos = m.Position
local step = m.Velocity
if m.Action:Has(ActionFlags.SWIMMING) then
step = applyWaterCurrent(m, step)
end
nextPos += step
if nextPos.Y > m.WaterLevel - 80 then
nextPos = Util.SetY(nextPos, m.WaterLevel - 80)
m.Velocity *= Vector3.new(1, 0, 1)
end
local stepResult = performWaterFullStep(m, nextPos)
m.GfxAngle = m.FaceAngle * Vector3int16.new(-1, 1, 1)
m.GfxPos = m.Position
return stepResult
end
local function updateWaterPitch(m: Mario)
local gfxAngle = m.GfxAngle
if gfxAngle.X > 0 then
local angle = 60 * Util.Sins(gfxAngle.X) * Util.Sins(gfxAngle.X)
m.GfxPos += Vector3.new(0, angle, 0)
end
if gfxAngle.X < 0 then
local x = gfxAngle.X * 6 / 10
gfxAngle = Util.SetX(gfxAngle, x)
end
if gfxAngle.X > 0 then
local x = gfxAngle.X * 10 / 8
gfxAngle = Util.SetX(gfxAngle, x)
end
m.GfxAngle = gfxAngle
end
local function stationarySlowDown(m: Mario)
local buoyancy = getBuoyancy(m)
m.AngleVel *= Vector3int16.new(0, 0, 1)
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 1, 1)
local faceY = m.FaceAngle.Y
local faceX = Util.ApproachInt(m.FaceAngle.X, 0, 0x200, 0x200)
local faceZ = Util.ApproachInt(m.FaceAngle.Z, 0, 0x100, 0x100)
local velY = Util.ApproachFloat(m.Velocity.Y, buoyancy, 2, 1)
local velX = m.ForwardVel * Util.Coss(faceX) * Util.Sins(faceY)
local velZ = m.ForwardVel * Util.Coss(faceX) * Util.Coss(faceY)
m.FaceAngle = Vector3int16.new(faceX, faceY, faceZ)
m.Velocity = Vector3.new(velX, velY, velZ)
end
local function updateSwimmingSpeed(m: Mario, maybeDecelThreshold: number?)
local buoyancy = getBuoyancy(m)
local decelThreshold = maybeDecelThreshold or MIN_SWIM_SPEED
if m.Action:Has(ActionFlags.STATIONARY) then
m.ForwardVel -= 2
end
m.ForwardVel = math.clamp(m.ForwardVel, 0, 28)
if m.ForwardVel > decelThreshold then
m.ForwardVel -= 0.5
end
m.Velocity = Vector3.new(
m.ForwardVel * Util.Coss(m.FaceAngle.X) * Util.Sins(m.FaceAngle.Y),
m.ForwardVel * Util.Sins(m.FaceAngle.X) + buoyancy,
m.ForwardVel * Util.Coss(m.FaceAngle.X) * Util.Coss(m.FaceAngle.Y)
)
end
local function updateSwimmingYaw(m: Mario)
local targetYawVel = -Util.SignedShort(10 * m.Controller.StickX)
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 velY = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x10, 0x20)
m.AngleVel = Util.SetY(m.AngleVel, velY)
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 velY = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x20, 0x10)
m.AngleVel = Util.SetY(m.AngleVel, velY)
end
else
local velY = Util.ApproachInt(m.AngleVel.Y, 0, 0x40, 0x40)
m.AngleVel = Util.SetY(m.AngleVel, velY)
end
m.FaceAngle += Vector3int16.new(0, m.AngleVel.Y, 0)
m.FaceAngle = Util.SetZ(m.FaceAngle, -m.AngleVel.Y * 8)
end
local function updateSwimmingPitch(m: Mario)
local targetPitch = -Util.SignedShort(252 * m.Controller.StickY)
-- stylua: ignore
local pitchVel = if m.FaceAngle.X < 0
then 0x100
else 0x200
if m.FaceAngle.X < targetPitch then
m.FaceAngle += Vector3int16.new(pitchVel, 0, 0)
if m.FaceAngle.X > targetPitch then
m.FaceAngle = Util.SetX(m.FaceAngle, targetPitch)
end
elseif m.FaceAngle.X > targetPitch then
m.FaceAngle -= Vector3int16.new(pitchVel, 0, 0)
if m.FaceAngle.X < targetPitch then
m.FaceAngle = Util.SetX(m.FaceAngle, targetPitch)
end
end
end
local function commonIdleStep(m: Mario, anim: Animation, maybeAccel: number?)
local accel = maybeAccel or 0
local bodyState = m.BodyState
local headAngleX = bodyState.HeadAngle.X
updateSwimmingYaw(m)
updateSwimmingPitch(m)
updateSwimmingSpeed(m)
performWaterStep(m)
updateWaterPitch(m)
if m.FaceAngle.X > 0 then
headAngleX = Util.ApproachInt(headAngleX, m.FaceAngle.X / 2, 0x80, 0x200)
else
headAngleX = Util.ApproachInt(headAngleX, 0, 0x200, 0x200)
end
if accel == 0 then
m:SetAnimation(anim)
else
m:SetAnimationWithAccel(anim, accel)
end
setSwimmingAtSurfaceParticles(m, ParticleFlags.IDLE_WATER_WAVE)
end
local function resetBobVariables(m: Mario)
sBobTimer = 0
sBobIncrement = 0x800
sBobHeight = m.FaceAngle.X / 256 + 20
end
local function surfaceSwimBob(m: Mario)
if sBobIncrement ~= 0 and m.Position.Y > m.WaterLevel - 85 and m.FaceAngle.Y >= 0 then
sBobTimer += sBobIncrement
if sBobTimer >= 0 then
m.GfxPos += Vector3.new(0, sBobHeight * Util.Sins(sBobTimer), 0)
return
end
end
sBobIncrement = 0
end
local function commonSwimmingStep(m: Mario, swimStrength: number)
local waterStep
updateSwimmingYaw(m)
updateSwimmingPitch(m)
updateSwimmingSpeed(m, swimStrength / 10)
-- do water step
waterStep = performWaterStep(m)
if waterStep == WaterStep.HIT_FLOOR then
local floorPitch = -m:FindFloorSlope(-0x8000)
if m.FaceAngle.X < floorPitch then
m.FaceAngle = Util.SetX(m.FaceAngle, floorPitch)
end
elseif waterStep == WaterStep.HIT_CEILING then
if m.FaceAngle.Y > -0x3000 then
m.FaceAngle -= Vector3int16.new(0, 0x100, 0)
end
elseif waterStep == WaterStep.HIT_WALL then
if m.Controller.StickY == 0 then
if m.FaceAngle.X > 0 then
m.FaceAngle += Vector3int16.new(0x200, 0, 0)
if m.FaceAngle.X > 0x3F00 then
m.FaceAngle = Util.SetX(m.FaceAngle, 0x3F00)
end
else
m.FaceAngle -= Vector3int16.new(0x200, 0, 0)
if m.FaceAngle.X < -0x3F00 then
m.FaceAngle = Util.SetX(m.FaceAngle, -0x3F00)
end
end
end
end
local headAngle = m.BodyState.HeadAngle
updateWaterPitch(m)
local angleX = Util.ApproachInt(headAngle.X, 0, 0x200, 0x200)
m.BodyState.HeadAngle = Util.SetX(headAngle, angleX)
surfaceSwimBob(m)
setSwimmingAtSurfaceParticles(m, ParticleFlags.WAVE_TRAIL)
end
local function playSwimmingNoise(m: Mario)
local animFrame = m.AnimFrame
if animFrame == 0 or animFrame == 12 then
m:PlaySound(Sounds.ACTION_SWIM_KICK)
end
end
local function checkWaterJump(m: Mario)
local probe = Util.SignedInt(m.Position.Y + 1.5)
if m.Input:Has(InputFlags.A_PRESSED) then
if probe >= m.WaterLevel - 80 and m.FaceAngle.X >= 0 and m.Controller.StickY < -60 then
m.AngleVel = Vector3int16.new()
m.Velocity = Util.SetY(m.Velocity, 62)
return m:SetAction(Action.WATER_JUMP)
end
end
return false
end
local function playMetalWaterJumpingSound(m: Mario, landing: boolean)
if not m.Flags:Has(MarioFlags.ACTION_SOUND_PLAYED) then
m.ParticleFlags:Add(ParticleFlags.MIST_CIRCLE)
end
m:PlaySoundIfNoFlag(
landing and Sounds.ACTION_METAL_LAND_WATER or Sounds.ACTION_METAL_JUMP_WATER,
MarioFlags.ACTION_SOUND_PLAYED
)
end
local function playMetalWaterWalkingSound(m: Mario)
if m:IsAnimPastFrame(10) or m:IsAnimPastFrame(49) then
m:PlaySound(Sounds.ACTION_METAL_STEP_WATER)
m.ParticleFlags:Add(ParticleFlags.DUST)
end
end
local function updateMetalWaterWalkingSpeed(m: Mario)
local val = m.IntendedMag / 1.5
local floor = m.Floor
if m.ForwardVel <= 0 then
m.ForwardVel += 1.1
elseif m.ForwardVel <= val then
m.ForwardVel += 1.1 - m.ForwardVel / 43
elseif floor and floor.Normal.Y >= 0.95 then
m.ForwardVel -= 1
end
if m.ForwardVel > 32 then
m.ForwardVel = 32
end
local faceY = m.IntendedYaw - Util.ApproachInt(Util.SignedShort(m.IntendedYaw - m.FaceAngle.Y), 0, 0x800, 0x800)
m.FaceAngle = Util.SetY(m.FaceAngle, faceY)
m.SlideVelX = m.ForwardVel * Util.Sins(faceY)
m.SlideVelZ = m.ForwardVel * Util.Coss(faceY)
m.Velocity = Vector3.new(m.SlideVelX, 0, m.SlideVelZ)
end
local function updateMetalWaterJumpSpeed(m: Mario)
local waterSurface = m.WaterLevel - 100
if m.Velocity.Y > 0 and m.Position.Y > waterSurface then
return true
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
local intendedDYaw = Util.SignedShort(m.IntendedYaw - m.FaceAngle.Y)
m.ForwardVel += 0.8 * Util.Coss(intendedDYaw)
m.FaceAngle += Vector3int16.new(0, 0x200 * Util.Sins(intendedDYaw), 0)
else
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 0, 0.25, 0.25)
end
if m.ForwardVel > 16 then
m.ForwardVel -= 1
end
if m.ForwardVel < 0 then
m.ForwardVel += 2
end
local velY = m.Velocity.Y
local velX = m.ForwardVel * Util.Sins(m.FaceAngle.Y)
local velZ = m.ForwardVel * Util.Coss(m.FaceAngle.Y)
m.SlideVelX = velX
m.SlideVelZ = velZ
m.Velocity = Vector3.new(velX, velY, velZ)
return false
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local DEF_ACTION: (number, (Mario) -> boolean) -> () = System.RegisterAction
DEF_ACTION(Action.WATER_IDLE, function(m: Mario)
local val = 0x10000
if m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.METAL_WATER_FALLING, 1)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.WATER_PUNCH)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.BREASTSTROKE)
end
if m.FaceAngle.X < -0x1000 then
val = 0x30000
end
commonIdleStep(m, Animations.WATER_IDLE, val)
return false
end)
DEF_ACTION(Action.WATER_ACTION_END, function(m: Mario)
if m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.METAL_WATER_FALLING, 1)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.WATER_PUNCH)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.BREASTSTROKE)
end
commonIdleStep(m, Animations.WATER_ACTION_END)
if m:IsAnimAtEnd() then
m:SetAction(Action.WATER_IDLE)
end
return false
end)
DEF_ACTION(Action.BREASTSTROKE, function(m: Mario)
if m.ActionArg == 0 then
sSwimStrength = MIN_SWIM_STRENGTH
end
if m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.METAL_WATER_FALLING, 1)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.WATER_PUNCH)
end
m.ActionTimer += 1
if m.ActionTimer == 14 then
return m:SetAction(Action.FLUTTER_KICK)
end
if checkWaterJump(m) then
return true
end
if m.ActionTimer < 6 then
m.ForwardVel += 0.5
end
if m.ActionTimer >= 9 then
m.ForwardVel += 1.5
end
if m.ActionTimer >= 2 then
if m.ActionTimer < 6 and m.Input:Has(InputFlags.A_PRESSED) then
m.ActionState = 1
end
if m.ActionTimer == 9 and m.ActionState == 1 then
m:SetAnimToFrame(0)
m.ActionState = 0
m.ActionTimer = 1
sSwimStrength = MIN_SWIM_STRENGTH
end
end
if m.ActionTimer == 1 then
m:PlaySound(sSwimStrength == MIN_SWIM_STRENGTH and Sounds.ACTION_SWIM or Sounds.ACTION_SWIM_FAST)
resetBobVariables(m)
end
m:SetAnimation(Animations.SWIM_PART1)
commonSwimmingStep(m, sSwimStrength)
return false
end)
DEF_ACTION(Action.SWIMMING_END, function(m: Mario)
if m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.METAL_WATER_FALLING, 1)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.WATER_PUNCH)
end
if m.ActionTimer >= 15 then
return m:SetAction(Action.WATER_ACTION_END)
end
if checkWaterJump(m) then
return true
end
if m.Input:Has(InputFlags.A_DOWN) and m.ActionTimer >= 7 then
if m.ActionTimer == 7 and sSwimStrength < 280 then
sSwimStrength += 10
end
return m:SetAction(Action.BREASTSTROKE, 1)
end
if m.ActionTimer >= 7 then
sSwimStrength = MIN_SWIM_STRENGTH
end
m.ActionTimer += 1
m.ForwardVel -= 0.25
m:SetAnimation(Animations.SWIM_PART2)
commonSwimmingStep(m, sSwimStrength)
return false
end)
DEF_ACTION(Action.FLUTTER_KICK, function(m: Mario)
if m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.METAL_WATER_FALLING, 1)
end
if m.Input:Has(InputFlags.B_PRESSED) then
return m:SetAction(Action.WATER_PUNCH)
end
if not m.Input:Has(InputFlags.A_DOWN) then
if m.ActionTimer == 0 and sSwimStrength < 280 then
sSwimStrength += 10
end
return m:SetAction(Action.SWIMMING_END)
end
m.ForwardVel = Util.ApproachFloat(m.ForwardVel, 12, 0.1, 0.15)
m.ActionTimer = 1
sSwimStrength = MIN_SWIM_STRENGTH
if m.ForwardVel < 14 then
playSwimmingNoise(m)
m:SetAnimation(Animations.FLUTTERKICK)
end
commonSwimmingStep(m, sSwimStrength)
return false
end)
DEF_ACTION(Action.WATER_PUNCH, function(m: Mario)
if m.ForwardVel < 7 then
m.ForwardVel += 1
end
updateSwimmingYaw(m)
updateSwimmingPitch(m)
updateSwimmingSpeed(m)
performWaterStep(m)
updateWaterPitch(m)
local headAngle = m.BodyState.HeadAngle
local angleX = Util.ApproachInt(headAngle.X, 0, 0x200, 0x200)
m.BodyState.HeadAngle = Util.SetX(headAngle, angleX)
m:PlaySoundIfNoFlag(Sounds.ACTION_SWIM, MarioFlags.ACTION_SOUND_PLAYED)
if m.ActionState == 0 then
m:SetAnimation(Animations.WATER_GRAB_OBJ_PART1)
if m:IsAnimAtEnd() then
m.ActionState = 1
end
elseif m.ActionState == 1 then
m:SetAnimation(Animations.WATER_GRAB_OBJ_PART2)
if m:IsAnimAtEnd() then
m:SetAction(Action.WATER_ACTION_END)
end
end
return false
end)
DEF_ACTION(Action.WATER_PLUNGE, function(m: Mario)
local stepResult
local endVSpeed = swimmingNearSurface(m) and 0 or -5
local hasMetalCap = m.Flags:Has(MarioFlags.METAL_CAP)
local isDiving = m.PrevAction:Has(ActionFlags.DIVING) or m.Input:Has(InputFlags.A_DOWN)
m.ActionTimer += 1
stationarySlowDown(m)
stepResult = performWaterStep(m)
if m.ActionState == 0 then
m:PlaySound(Sounds.ACTION_WATER_ENTER)
if m.PeakHeight - m.Position.Y > 1150 then
m:PlaySound(Sounds.MARIO_HAHA)
end
m.ParticleFlags:Add(ParticleFlags.WATER_SPLASH)
m.ActionState = 1
end
if stepResult == WaterStep.HIT_FLOOR or m.Velocity.Y >= endVSpeed or m.ActionTimer > 20 then
if hasMetalCap then
m:SetAction(Action.METAL_WATER_FALLING)
elseif isDiving then
m:SetAction(Action.FLUTTER_KICK)
else
m:SetAction(Action.WATER_ACTION_END)
end
sBobIncrement = 0
end
if hasMetalCap then
m:SetAnimation(Animations.GENERAL_FALL)
elseif isDiving then
m:SetAnimation(Animations.FLUTTERKICK)
else
m:SetAnimation(Animations.WATER_ACTION_END)
end
m.Flags:Add(ParticleFlags.PLUNGE_BUBBLE)
return false
end)
DEF_ACTION(Action.METAL_WATER_STANDING, function(m: Mario)
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.METAL_WATER_JUMP)
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
return m:SetAction(Action.METAL_WATER_WALKING)
end
if m.ActionState == 0 then
m:SetAnimation(Animations.IDLE_HEAD_LEFT)
elseif m.ActionState == 1 then
m:SetAnimation(Animations.IDLE_HEAD_RIGHT)
elseif m.ActionState == 2 then
m:SetAnimation(Animations.IDLE_HEAD_CENTER)
end
if m:IsAnimAtEnd() then
m.ActionState += 1
if m.ActionState == 3 then
m.ActionState = 0
end
end
m:StopAndSetHeightToFloor()
if m.Position.Y >= m.WaterLevel - 150 then
m.ParticleFlags:Add(ParticleFlags.IDLE_WATER_WAVE)
end
return false
end)
DEF_ACTION(Action.METAL_WATER_WALKING, function(m: Mario)
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if m.Input:Has(InputFlags.A_PRESSED) then
return m:SetAction(Action.METAL_WATER_JUMP)
end
if m.Input:Has(InputFlags.NO_MOVEMENT) then
return m:SetAction(Action.METAL_WATER_STANDING)
end
local accel = Util.SignedInt(m.ForwardVel / 4 * 0x10000)
local groundStep
if accel < 0x1000 then
accel = 0x1000
end
m:SetAnimationWithAccel(Animations.WALKING, accel)
playMetalWaterWalkingSound(m)
updateMetalWaterWalkingSpeed(m)
groundStep = m:PerformGroundStep()
if groundStep == GroundStep.LEFT_GROUND then
m:SetAction(Action.METAL_WATER_FALLING, 1)
elseif groundStep == GroundStep.HIT_WALL then
m.ForwardVel = 0
end
return false
end)
DEF_ACTION(Action.METAL_WATER_JUMP, function(m: Mario)
local airStep
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if updateMetalWaterJumpSpeed(m) then
return m:SetAction(Action.WATER_JUMP, 1)
end
playMetalWaterJumpingSound(m, false)
m:SetAnimation(Animations.SINGLE_JUMP)
airStep = m:PerformAirStep()
if airStep == AirStep.LANDED then
m:SetAction(Action.METAL_WATER_JUMP_LAND)
elseif airStep == AirStep.HIT_WALL then
m.ForwardVel = 0
end
return false
end)
DEF_ACTION(Action.METAL_WATER_FALLING, function(m: Mario)
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
m.FaceAngle += Vector3int16.new(0, 0x400 * Util.Sins(m.IntendedYaw - m.FaceAngle.Y), 0)
end
m:SetAnimation(m.ActionArg == 0 and Animations.GENERAL_FALL or Animations.FALL_FROM_WATER)
stationarySlowDown(m)
if bit32.btest(performWaterStep(m), WaterStep.HIT_FLOOR) then
m:SetAction(Action.METAL_WATER_FALL_LAND)
end
return false
end)
DEF_ACTION(Action.METAL_WATER_JUMP_LAND, function(m: Mario)
playMetalWaterJumpingSound(m, true)
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
return m:SetAction(Action.METAL_WATER_WALKING)
end
m:StopAndSetHeightToFloor()
m:SetAnimation(Animations.LAND_FROM_SINGLE_JUMP)
if m:IsAnimAtEnd() then
return m:SetAction(Action.METAL_WATER_STANDING)
end
return false
end)
DEF_ACTION(Action.METAL_WATER_FALL_LAND, function(m: Mario)
playMetalWaterJumpingSound(m, true)
if not m.Flags:Has(MarioFlags.METAL_CAP) then
return m:SetAction(Action.WATER_IDLE)
end
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
return m:SetAction(Action.METAL_WATER_WALKING)
end
m:StopAndSetHeightToFloor()
m:SetAnimation(Animations.GENERAL_LAND)
if m:IsAnimAtEnd() then
return m:SetAction(Action.METAL_WATER_STANDING)
end
return false
end)