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)