Implemented swimming.
This commit is contained in:
parent
d4000b30fa
commit
cfb04d9325
16 changed files with 1311 additions and 147 deletions
|
@ -6,7 +6,7 @@ return {
|
|||
OFF_FLOOR = 0x0004,
|
||||
ABOVE_SLIDE = 0x0008,
|
||||
FIRST_PERSON = 0x0010,
|
||||
UNKNOWN_5 = 0x0020,
|
||||
NO_MOVEMENT = 0x0020,
|
||||
SQUISHED = 0x0040,
|
||||
A_DOWN = 0x0080,
|
||||
IN_POISON_GAS = 0x0100,
|
||||
|
|
|
@ -6,7 +6,7 @@ return {
|
|||
OFF_FLOOR = 0x0004,
|
||||
ABOVE_SLIDE = 0x0008,
|
||||
FIRST_PERSON = 0x0010,
|
||||
UNKNOWN_5 = 0x0020,
|
||||
NO_MOVEMENT = 0x0020,
|
||||
SQUISHED = 0x0040,
|
||||
A_DOWN = 0x0080,
|
||||
IN_POISON_GAS = 0x0100,
|
||||
|
|
|
@ -35,31 +35,6 @@ local function playFlipSounds(m: Mario, frame1: number, frame2: number, frame3:
|
|||
end
|
||||
end
|
||||
|
||||
local function playFarFallSound(m: Mario)
|
||||
if m.Flags:Has(MarioFlags.FALLING_FAR) then
|
||||
return
|
||||
end
|
||||
|
||||
local action = m.Action
|
||||
|
||||
if action() == Action.TWIRLING then
|
||||
return
|
||||
end
|
||||
|
||||
if action() == Action.FLYING then
|
||||
return
|
||||
end
|
||||
|
||||
if action:Has(ActionFlags.INVULNERABLE) then
|
||||
return
|
||||
end
|
||||
|
||||
if m.PeakHeight - m.Position.Y > 1150 then
|
||||
m:PlaySound(Sounds.MARIO_WAAAOOOW)
|
||||
m.Flags:Add(MarioFlags.FALLING_FAR)
|
||||
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)
|
||||
|
@ -73,7 +48,7 @@ local function lavaBoostOnWall(m: Mario)
|
|||
|
||||
if wall then
|
||||
local angle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, angle)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, angle)
|
||||
end
|
||||
|
||||
if m.ForwardVel < 24 then
|
||||
|
@ -210,30 +185,30 @@ local function updateFlyingYaw(m: Mario)
|
|||
m.AngleVel += Vector3int16.new(0, 0x40, 0)
|
||||
|
||||
if m.AngleVel.Y > 0x10 then
|
||||
m.AngleVel = Util.SetYint16(m.AngleVel, 0x10)
|
||||
m.AngleVel = Util.SetY(m.AngleVel, 0x10)
|
||||
end
|
||||
else
|
||||
local y = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x10, 0x20)
|
||||
m.AngleVel = Util.SetYint16(m.AngleVel, y)
|
||||
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.SetYint16(m.AngleVel, -0x10)
|
||||
m.AngleVel = Util.SetY(m.AngleVel, -0x10)
|
||||
end
|
||||
else
|
||||
local y = Util.ApproachInt(m.AngleVel.Y, targetYawVel, 0x20, 0x10)
|
||||
m.AngleVel = Util.SetYint16(m.AngleVel, y)
|
||||
m.AngleVel = Util.SetY(m.AngleVel, y)
|
||||
end
|
||||
else
|
||||
local y = Util.ApproachInt(m.AngleVel.Y, 0, 0x40)
|
||||
m.AngleVel = Util.SetYint16(m.AngleVel, y)
|
||||
m.AngleVel = Util.SetY(m.AngleVel, y)
|
||||
end
|
||||
|
||||
m.FaceAngle += Vector3int16.new(0, m.AngleVel.Y, 0)
|
||||
m.FaceAngle = Util.SetZint16(m.FaceAngle, 20 * -m.AngleVel.Y)
|
||||
m.FaceAngle = Util.SetZ(m.FaceAngle, 20 * -m.AngleVel.Y)
|
||||
end
|
||||
|
||||
local function updateFlyingPitch(m: Mario)
|
||||
|
@ -244,26 +219,26 @@ local function updateFlyingPitch(m: Mario)
|
|||
m.AngleVel += Vector3int16.new(0x40, 0, 0)
|
||||
|
||||
if m.AngleVel.X > 0x20 then
|
||||
m.AngleVel = Util.SetXint16(m.AngleVel, 0x20)
|
||||
m.AngleVel = Util.SetX(m.AngleVel, 0x20)
|
||||
end
|
||||
else
|
||||
local x = Util.ApproachInt(m.AngleVel.X, targetPitchVel, 0x20, 0x40)
|
||||
m.AngleVel = Util.SetXint16(m.AngleVel, x)
|
||||
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.SetXint16(m.AngleVel, -0x20)
|
||||
m.AngleVel = Util.SetX(m.AngleVel, -0x20)
|
||||
end
|
||||
else
|
||||
local x = Util.ApproachInt(m.AngleVel.X, targetPitchVel, 0x40, 0x20)
|
||||
m.AngleVel = Util.SetXint16(m.AngleVel, x)
|
||||
m.AngleVel = Util.SetX(m.AngleVel, x)
|
||||
end
|
||||
else
|
||||
local x = Util.ApproachInt(m.AngleVel.X, 0, 0x40)
|
||||
m.AngleVel = Util.SetXint16(m.AngleVel, x)
|
||||
m.AngleVel = Util.SetX(m.AngleVel, x)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -289,11 +264,11 @@ local function updateFlying(m: Mario)
|
|||
m.FaceAngle += Vector3int16.new(m.AngleVel.X, 0, 0)
|
||||
|
||||
if m.FaceAngle.X > 0x2AAA then
|
||||
m.FaceAngle = Util.SetXint16(m.FaceAngle, 0x2AAA)
|
||||
m.FaceAngle = Util.SetX(m.FaceAngle, 0x2AAA)
|
||||
end
|
||||
|
||||
if m.FaceAngle.X < -0x2AAA then
|
||||
m.FaceAngle = Util.SetXint16(m.FaceAngle, -0x2AAA)
|
||||
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
|
||||
end
|
||||
|
||||
local velX = Util.Coss(m.FaceAngle.X) * Util.Sins(m.FaceAngle.Y)
|
||||
|
@ -584,7 +559,7 @@ DEF_ACTION(Action.TWIRLING, function(m: Mario)
|
|||
end
|
||||
|
||||
local yVel = Util.ApproachInt(m.AngleVel.Y, yawVelTarget, 0x200)
|
||||
m.AngleVel = Util.SetYint16(m.AngleVel, yVel)
|
||||
m.AngleVel = Util.SetY(m.AngleVel, yVel)
|
||||
m.TwirlYaw += yVel
|
||||
|
||||
m:SetAnimation(if m.ActionArg == 0 then Animations.START_TWIRL else Animations.TWIRL)
|
||||
|
@ -629,11 +604,11 @@ DEF_ACTION(Action.DIVE, function(m: Mario)
|
|||
m.FaceAngle -= Vector3int16.new(0x200, 0, 0)
|
||||
|
||||
if m.FaceAngle.X < -0x2AAA then
|
||||
m.FaceAngle = Util.SetXint16(m.FaceAngle, -0x2AAA)
|
||||
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
|
||||
end
|
||||
end
|
||||
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, -m.FaceAngle.X)
|
||||
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)
|
||||
|
@ -655,6 +630,30 @@ DEF_ACTION(Action.DIVE, function(m: Mario)
|
|||
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
|
||||
|
||||
|
@ -678,7 +677,7 @@ DEF_ACTION(Action.STEEP_JUMP, function(m: Mario)
|
|||
end
|
||||
|
||||
m:SetAnimation(Animations.SINGLE_JUMP)
|
||||
m.GfxAngle = Util.SetYint16(m.GfxAngle, m.SteepJumpYaw)
|
||||
m.GfxAngle = Util.SetY(m.GfxAngle, m.SteepJumpYaw)
|
||||
|
||||
return false
|
||||
end)
|
||||
|
@ -869,7 +868,7 @@ DEF_ACTION(Action.THROWN_FORWARD, function(m: Mario)
|
|||
pitch = 0x1800
|
||||
end
|
||||
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, pitch + 0x1800)
|
||||
m.GfxAngle = Util.SetX(m.GfxAngle, pitch + 0x1800)
|
||||
end
|
||||
|
||||
m.ForwardVel *= 0.98
|
||||
|
@ -1060,7 +1059,7 @@ DEF_ACTION(Action.SLIDE_KICK, function(m: Mario)
|
|||
tilt = 0x1800
|
||||
end
|
||||
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, tilt)
|
||||
m.GfxAngle = Util.SetX(m.GfxAngle, tilt)
|
||||
end
|
||||
elseif stepResult == AirStep.LANDED then
|
||||
if m.ActionState == 0 and m.Velocity.Y < 0 then
|
||||
|
@ -1154,8 +1153,8 @@ DEF_ACTION(Action.FLYING, function(m: Mario)
|
|||
end
|
||||
|
||||
if stepResult == AirStep.NONE then
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, -m.FaceAngle.X)
|
||||
m.GfxAngle = Util.SetZint16(m.GfxAngle, m.FaceAngle.Z)
|
||||
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)
|
||||
|
@ -1187,11 +1186,11 @@ DEF_ACTION(Action.FLYING, function(m: Mario)
|
|||
m.FaceAngle -= Vector3int16.new(0x200, 0, 0)
|
||||
|
||||
if m.FaceAngle.X < -0x2AAA then
|
||||
m.FaceAngle = Util.SetXint16(m.FaceAngle, -0x2AAA)
|
||||
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2AAA)
|
||||
end
|
||||
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, -m.FaceAngle.X)
|
||||
m.GfxAngle = Util.SetZint16(m.GfxAngle, m.FaceAngle.Z)
|
||||
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)
|
||||
|
|
|
@ -157,7 +157,7 @@ end
|
|||
|
||||
local function beginWalkingAction(m: Mario, forwardVel: number, action: number, actionArg: number?)
|
||||
m:SetForwardVel(forwardVel)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.IntendedYaw)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.IntendedYaw)
|
||||
return m:SetAction(action, actionArg)
|
||||
end
|
||||
|
||||
|
@ -177,7 +177,7 @@ local function checkLedgeClimbDown(m: Mario)
|
|||
m.Position = pos
|
||||
|
||||
m.FaceAngle *= Vector3int16.new(0, 1, 1)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, wallAngle + 0x8000)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, wallAngle + 0x8000)
|
||||
|
||||
m:SetAction(Action.LEDGE_CLIMB_DOWN)
|
||||
m:SetAnimation(Animations.CLIMB_DOWN_LEDGE)
|
||||
|
@ -259,7 +259,7 @@ local function updateSlidingAngle(m: Mario, accel: number, lossFactor: number)
|
|||
end
|
||||
end
|
||||
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.SlideYaw + newFacingDYaw)
|
||||
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)
|
||||
|
@ -450,7 +450,7 @@ local function updateWalkingSpeed(m: Mario)
|
|||
local currY = Util.SignedShort(m.IntendedYaw - m.FaceAngle.Y)
|
||||
local faceY = m.IntendedYaw - Util.ApproachInt(currY, 0, 0x800)
|
||||
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, faceY)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, faceY)
|
||||
applySlopeAccel(m)
|
||||
end
|
||||
|
||||
|
@ -485,7 +485,7 @@ end
|
|||
|
||||
local function beginBrakingAction(m: Mario)
|
||||
if m.ActionState == 1 then
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.ActionArg)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.ActionArg)
|
||||
return m:SetAction(Action.STANDING_AGAINST_WALL)
|
||||
end
|
||||
|
||||
|
@ -575,7 +575,7 @@ local function animAndAudioForWalk(m: Mario)
|
|||
walkingPitch = Util.SignedShort(walkingPitch)
|
||||
|
||||
m.WalkingPitch = walkingPitch
|
||||
m.GfxAngle = Util.SetXint16(m.GfxAngle, walkingPitch)
|
||||
m.GfxAngle = Util.SetX(m.GfxAngle, walkingPitch)
|
||||
end
|
||||
|
||||
local function pushOrSidleWall(m: Mario, startPos: Vector3)
|
||||
|
@ -617,8 +617,8 @@ local function pushOrSidleWall(m: Mario, startPos: Vector3)
|
|||
m.ActionState = 1
|
||||
m.ActionArg = Util.SignedShort(wallAngle + 0x8000)
|
||||
|
||||
m.GfxAngle = Util.SetYint16(m.GfxAngle, m.ActionArg)
|
||||
m.GfxAngle = Util.SetZint16(m.GfxAngle, m:FindFloorSlope(0x4000))
|
||||
m.GfxAngle = Util.SetY(m.GfxAngle, m.ActionArg)
|
||||
m.GfxAngle = Util.SetZ(m.GfxAngle, m:FindFloorSlope(0x4000))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -871,7 +871,7 @@ DEF_ACTION(Action.WALKING, function(m: Mario)
|
|||
return true
|
||||
end
|
||||
|
||||
if m.Input:Has(InputFlags.UNKNOWN_5) then
|
||||
if m.Input:Has(InputFlags.NO_MOVEMENT) then
|
||||
return beginBrakingAction(m)
|
||||
end
|
||||
|
||||
|
@ -1128,7 +1128,7 @@ DEF_ACTION(Action.CRAWLING, function(m: Mario)
|
|||
return true
|
||||
end
|
||||
|
||||
if m.Input:Has(InputFlags.UNKNOWN_5) then
|
||||
if m.Input:Has(InputFlags.NO_MOVEMENT) then
|
||||
return m:SetAction(Action.STOP_CRAWLING)
|
||||
end
|
||||
|
||||
|
@ -1183,7 +1183,7 @@ DEF_ACTION(Action.BURNING_GROUND, function(m: Mario)
|
|||
|
||||
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
|
||||
local faceY = m.IntendedYaw - Util.ApproachFloat(m.IntendedYaw - m.FaceAngle.Y, 0, 0x600)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, faceY)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, faceY)
|
||||
end
|
||||
|
||||
applySlopeAccel(m)
|
||||
|
|
|
@ -43,7 +43,7 @@ local function checkCommonIdleCancels(m: Mario)
|
|||
end
|
||||
|
||||
if m.Input:Has(InputFlags.NONZERO_ANALOG) then
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.IntendedYaw)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.IntendedYaw)
|
||||
return m:SetAction(Action.WALKING)
|
||||
end
|
||||
|
||||
|
|
6
client/Mario/Submerged/init.meta.json
Normal file
6
client/Mario/Submerged/init.meta.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"properties": {
|
||||
"Disabled": true,
|
||||
"RunContext": "Client"
|
||||
}
|
||||
}
|
857
client/Mario/Submerged/init.server.lua
Normal file
857
client/Mario/Submerged/init.server.lua
Normal file
|
@ -0,0 +1,857 @@
|
|||
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(sBobHeight * Util.Sins(sBobTimer))
|
||||
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)
|
|
@ -479,7 +479,7 @@ function Mario.SetSteepJumpAction(m: Mario)
|
|||
local x = Util.Coss(faceAngleTemp) * m.ForwardVel * 0.75
|
||||
|
||||
m.ForwardVel = math.sqrt(y * y + x * x)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, Util.Atan2s(x, y) + angleTemp)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, Util.Atan2s(x, y) + angleTemp)
|
||||
end
|
||||
|
||||
m:SetAction(Action.STEEP_JUMP, 0)
|
||||
|
@ -536,11 +536,11 @@ function Mario.SetActionAirborne(m: Mario, action: number, actionArg: number)
|
|||
elseif action == Action.SIDE_FLIP then
|
||||
m:SetYVelBasedOnFSpeed(62, 0)
|
||||
m.ForwardVel = 8
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.IntendedYaw)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.IntendedYaw)
|
||||
elseif action == Action.STEEP_JUMP then
|
||||
m.AnimReset = true
|
||||
m:SetYVelBasedOnFSpeed(42, 0.25)
|
||||
m.FaceAngle = Util.SetXint16(m.FaceAngle, -0x2000)
|
||||
m.FaceAngle = Util.SetX(m.FaceAngle, -0x2000)
|
||||
elseif action == Action.LAVA_BOOST then
|
||||
m.Velocity = Util.SetY(m.Velocity, 84)
|
||||
|
||||
|
@ -847,7 +847,7 @@ function Mario.BonkReflection(m: Mario, negateSpeed: boolean?)
|
|||
|
||||
if wall ~= nil then
|
||||
local wallAngle = Util.Atan2s(wall.Normal.Z, wall.Normal.X)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, wallAngle - (m.FaceAngle.Y - wallAngle))
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, wallAngle - (m.FaceAngle.Y - wallAngle))
|
||||
m:PlaySound(if m.Flags:Has(MarioFlags.METAL_CAP) then Sounds.ACTION_METAL_BONK else Sounds.ACTION_BONK)
|
||||
else
|
||||
m:PlaySound(Sounds.ACTION_HIT)
|
||||
|
@ -865,10 +865,10 @@ function Mario.PushOffSteepFloor(m: Mario, action: number, actionArg: number?)
|
|||
|
||||
if floorDYaw > -0x4000 and floorDYaw < 0x4000 then
|
||||
m.ForwardVel = 16
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.FloorAngle)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.FloorAngle)
|
||||
else
|
||||
m.ForwardVel = -16
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, m.FloorAngle + 0x8000)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, m.FloorAngle + 0x8000)
|
||||
end
|
||||
|
||||
m:SetAction(action, actionArg)
|
||||
|
@ -998,7 +998,7 @@ function Mario.CheckLedgeGrab(m: Mario, wall: RaycastResult, intendedPos: Vector
|
|||
m.FloorAngle = Util.Atan2s(ledgeFloor.Normal.Z, ledgeFloor.Normal.X)
|
||||
|
||||
m.FaceAngle *= Vector3int16.new(0, 1, 1)
|
||||
m.FaceAngle = Util.SetYint16(m.FaceAngle, Util.Atan2s(wall.Normal.Z, wall.Normal.X) + 0x8000)
|
||||
m.FaceAngle = Util.SetY(m.FaceAngle, Util.Atan2s(wall.Normal.Z, wall.Normal.X) + 0x8000)
|
||||
end
|
||||
|
||||
return ledgeFloor ~= nil
|
||||
|
@ -1014,7 +1014,7 @@ function Mario.PerformAirQuarterStep(m: Mario, intendedPos: Vector3, stepArg: nu
|
|||
nextPos = lowerPos
|
||||
|
||||
local floorHeight, floor = Util.FindFloor(nextPos)
|
||||
local ceilHeight, _ceil = Util.FindCeil(nextPos, floorHeight)
|
||||
local ceilHeight = Util.FindCeil(nextPos, floorHeight)
|
||||
|
||||
m.Wall = nil
|
||||
|
||||
|
@ -1310,7 +1310,7 @@ function Mario.UpdateInputs(m: Mario)
|
|||
m:UpdateGeometryInputs()
|
||||
|
||||
if not m.Input:Has(InputFlags.NONZERO_ANALOG, InputFlags.A_PRESSED) then
|
||||
m.Input:Add(InputFlags.UNKNOWN_5)
|
||||
m.Input:Add(InputFlags.NO_MOVEMENT)
|
||||
end
|
||||
|
||||
if m.WallKickTimer > 0 then
|
||||
|
@ -1335,11 +1335,8 @@ end
|
|||
|
||||
function Mario.UpdateCaps(m: Mario): Flags
|
||||
local flags = m.Flags
|
||||
local _action
|
||||
|
||||
if m.CapTimer > 0 then
|
||||
_action = m.Action
|
||||
|
||||
if m.CapTimer <= 60 then
|
||||
m.CapTimer -= 1
|
||||
end
|
||||
|
@ -1365,7 +1362,7 @@ function Mario.UpdateModel(m: Mario)
|
|||
modelState:Add(ModelFlags.NOISE_ALPHA)
|
||||
end
|
||||
|
||||
if flags:Has(bit32.bor(MarioFlags.METAL_CAP, MarioFlags.METAL_SHOCK)) then
|
||||
if flags:Has(MarioFlags.METAL_CAP, MarioFlags.METAL_SHOCK) then
|
||||
modelState:Add(ModelFlags.METAL)
|
||||
end
|
||||
|
||||
|
@ -1438,21 +1435,59 @@ end
|
|||
function Mario.HandleSpecialFloors(m: Mario)
|
||||
local floor = m.Floor
|
||||
|
||||
if floor then
|
||||
local part = floor.Instance :: BasePart
|
||||
|
||||
if not m.Action:Has(ActionFlags.AIR, ActionFlags.SWIMMING) then
|
||||
if part.Material == Enum.Material.CrackedLava then
|
||||
if not m.Flags:Has(MarioFlags.METAL_CAP) then
|
||||
m.HurtCounter += m.Flags:Has(MarioFlags.CAP_ON_HEAD) and 12 or 18
|
||||
end
|
||||
|
||||
m:SetAction(Action.LAVA_BOOST)
|
||||
if floor and not m.Action:Has(ActionFlags.AIR, ActionFlags.SWIMMING) then
|
||||
if floor.Material == Enum.Material.CrackedLava then
|
||||
if not m.Flags:Has(MarioFlags.METAL_CAP) then
|
||||
m.HurtCounter += m.Flags:Has(MarioFlags.CAP_ON_HEAD) and 12 or 18
|
||||
end
|
||||
|
||||
m:SetAction(Action.LAVA_BOOST)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Mario.SetWaterPlungeAction(m: Mario)
|
||||
m.ForwardVel /= 4
|
||||
m.Velocity *= Vector3.new(1, 0.5, 1)
|
||||
|
||||
-- This behavior sucks, feel free to enable if you want.
|
||||
-- m.Position = Util.SetY(m.Position, m.WaterLevel - 100)
|
||||
|
||||
m.FaceAngle *= Vector3int16.new(1, 1, 0)
|
||||
m.AngleVel *= 0
|
||||
|
||||
if not m.Action:Has(ActionFlags.DIVING) then
|
||||
m.FaceAngle *= Vector3int16.new(0, 1, 1)
|
||||
end
|
||||
|
||||
return m:SetAction(Action.WATER_PLUNGE)
|
||||
end
|
||||
|
||||
function Mario.PlayFarFallSound(m: Mario)
|
||||
if m.Flags:Has(MarioFlags.FALLING_FAR) then
|
||||
return
|
||||
end
|
||||
|
||||
local action = m.Action
|
||||
|
||||
if action() == Action.TWIRLING then
|
||||
return
|
||||
end
|
||||
|
||||
if action() == Action.FLYING then
|
||||
return
|
||||
end
|
||||
|
||||
if action:Has(ActionFlags.INVULNERABLE) then
|
||||
return
|
||||
end
|
||||
|
||||
if m.PeakHeight - m.Position.Y > 1150 then
|
||||
m:PlaySound(Sounds.MARIO_WAAAOOOW)
|
||||
m.Flags:Add(MarioFlags.FALLING_FAR)
|
||||
end
|
||||
end
|
||||
|
||||
function Mario.ExecuteAction(m: Mario): number
|
||||
if m.Action() == 0 then
|
||||
return 0
|
||||
|
@ -1490,7 +1525,43 @@ function Mario.ExecuteAction(m: Mario): number
|
|||
local action = actions[id]
|
||||
|
||||
if action then
|
||||
if not action(m) then
|
||||
local group = bit32.band(id, ActionGroups.GROUP_MASK)
|
||||
local cancel
|
||||
|
||||
if group ~= ActionGroups.SUBMERGED and m.Position.Y < m.WaterLevel - 100 then
|
||||
cancel = m:SetWaterPlungeAction()
|
||||
else
|
||||
if group == ActionGroups.AIRBORNE then
|
||||
m:PlayFarFallSound()
|
||||
elseif group == ActionGroups.SUBMERGED then
|
||||
if m.Position.Y > m.WaterLevel - 80 then
|
||||
if m.WaterLevel - 80 > m.FloorHeight then
|
||||
m.Position = Util.SetY(m.Position, m.WaterLevel - 80)
|
||||
else
|
||||
m.AngleVel *= 0
|
||||
cancel = m:SetAction(Action.WALKING)
|
||||
end
|
||||
end
|
||||
|
||||
m.QuicksandDepth = 0
|
||||
m.BodyState.HeadAngle *= Vector3int16.new(1, 0, 0)
|
||||
end
|
||||
|
||||
if cancel == nil then
|
||||
cancel = action(m)
|
||||
end
|
||||
end
|
||||
|
||||
if not cancel then
|
||||
if m.Input:Has(InputFlags.IN_WATER) then
|
||||
if group == ActionGroups.MOVING then
|
||||
m.ParticleFlags:Add(ParticleFlags.WAVE_TRAIL)
|
||||
m.ParticleFlags:Remove(ParticleFlags.DUST)
|
||||
elseif group == ActionGroups.STATIONARY then
|
||||
m.ParticleFlags:Add(ParticleFlags.IDLE_WATER_WAVE)
|
||||
end
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
else
|
||||
|
@ -1573,10 +1644,12 @@ function Mario.new(): Mario
|
|||
DoubleJumpTimer = 0,
|
||||
|
||||
FaceAngle = Vector3int16.new(),
|
||||
GfxAngle = Vector3int16.new(),
|
||||
AngleVel = Vector3int16.new(),
|
||||
ThrowMatrix = CFrame.identity,
|
||||
|
||||
GfxAngle = Vector3int16.new(),
|
||||
GfxPos = Vector3.zero,
|
||||
|
||||
SlideYaw = 0,
|
||||
TwirlYaw = 0,
|
||||
|
||||
|
|
|
@ -56,10 +56,12 @@ export type MarioState = {
|
|||
DoubleJumpTimer: number,
|
||||
|
||||
FaceAngle: Vector3int16,
|
||||
GfxAngle: Vector3int16,
|
||||
AngleVel: Vector3int16,
|
||||
ThrowMatrix: CFrame?,
|
||||
|
||||
GfxAngle: Vector3int16,
|
||||
GfxPos: Vector3,
|
||||
|
||||
SlideYaw: number,
|
||||
TwirlYaw: number,
|
||||
|
||||
|
|
|
@ -16,6 +16,19 @@ local VECTOR3_XZ = Vector3.one - Vector3.yAxis
|
|||
local TweenService = game:GetService("TweenService")
|
||||
local fadeOut = TweenInfo.new(0.5)
|
||||
|
||||
local waterPlane = Instance.new("BoxHandleAdornment")
|
||||
waterPlane.Size = Vector3.new(48, 0, 48)
|
||||
waterPlane.Adornee = workspace.Terrain
|
||||
waterPlane.Transparency = 0.5
|
||||
waterPlane.Name = "WaterPlane"
|
||||
|
||||
local focalPlane = waterPlane:Clone()
|
||||
focalPlane.Size = Vector3.new(4, 0, 4)
|
||||
focalPlane.Color3 = Color3.new(1, 0, 1)
|
||||
focalPlane.Name = "FocalPlane"
|
||||
focalPlane.Transparency = 0.1
|
||||
focalPlane.Parent = waterPlane
|
||||
|
||||
local CARDINAL = {
|
||||
-Vector3.xAxis,
|
||||
-Vector3.zAxis,
|
||||
|
@ -23,29 +36,33 @@ local CARDINAL = {
|
|||
Vector3.zAxis,
|
||||
}
|
||||
|
||||
function Util.SetX(vec: Vector3, x: number): Vector3
|
||||
return Vector3.new(x, vec.Y, vec.Z)
|
||||
local CONSTRUCTORS = {
|
||||
Vector3 = Vector3.new,
|
||||
Vector3int16 = Vector3int16.new,
|
||||
}
|
||||
|
||||
-- stylua: ignore
|
||||
local function vectorModifier(getArgs: (Vector3 | Vector3int16, number) -> (number, number, number)):
|
||||
((vec: Vector3, value: number) -> Vector3) &
|
||||
((vec: Vector3int16, value: number) -> Vector3int16)
|
||||
|
||||
return function (vector, new)
|
||||
local constructor = CONSTRUCTORS[typeof(vector)]
|
||||
return constructor(getArgs(vector, new))
|
||||
end
|
||||
end
|
||||
|
||||
function Util.SetXint16(vec: Vector3int16, x: number): Vector3int16
|
||||
return Vector3int16.new(x, vec.Y, vec.Z)
|
||||
end
|
||||
Util.SetX = vectorModifier(function(vector, x)
|
||||
return x, vector.Y, vector.Z
|
||||
end)
|
||||
|
||||
function Util.SetY(vec: Vector3, y: number): Vector3
|
||||
return Vector3.new(vec.X, y, vec.Z)
|
||||
end
|
||||
Util.SetY = vectorModifier(function(vector, y)
|
||||
return vector.X, y, vector.Z
|
||||
end)
|
||||
|
||||
function Util.SetYint16(vec: Vector3int16, y: number): Vector3int16
|
||||
return Vector3int16.new(vec.X, y, vec.Z)
|
||||
end
|
||||
|
||||
function Util.SetZ(vec: Vector3, z: number): Vector3
|
||||
return Vector3.new(vec.X, vec.Y, z)
|
||||
end
|
||||
|
||||
function Util.SetZint16(vec: Vector3int16, z: number): Vector3int16
|
||||
return Vector3int16.new(vec.X, vec.Y, z)
|
||||
end
|
||||
Util.SetZ = vectorModifier(function(vector, z)
|
||||
return vector.X, vector.Y, z
|
||||
end)
|
||||
|
||||
function Util.ToRoblox(v: Vector3)
|
||||
return v * Util.Scale
|
||||
|
@ -62,13 +79,32 @@ end
|
|||
function Util.ToRotation(v: Vector3int16): CFrame
|
||||
local angle = Util.ToEulerAngles(v)
|
||||
|
||||
-- stylua: ignore
|
||||
local matrix = CFrame.fromAxisAngle(Vector3.yAxis, angle.Y)
|
||||
* CFrame.fromAxisAngle(Vector3.xAxis, -angle.X)
|
||||
* CFrame.fromAxisAngle(Vector3.zAxis, -angle.Z)
|
||||
* CFrame.fromAxisAngle(Vector3.xAxis, -angle.X)
|
||||
* CFrame.fromAxisAngle(Vector3.zAxis, -angle.Z)
|
||||
|
||||
return matrix
|
||||
end
|
||||
|
||||
function Util.DebugWater(waterLevel: number)
|
||||
if script:GetAttribute("Debug") then
|
||||
local robloxLevel = (waterLevel * Util.Scale) + 0.01
|
||||
local focus = workspace.CurrentCamera.Focus
|
||||
|
||||
local x = math.floor(focus.X / 4) * 4
|
||||
local z = math.floor(focus.Z / 4) * 4
|
||||
|
||||
local cf = CFrame.new(x, robloxLevel, z)
|
||||
waterPlane.Parent = script
|
||||
|
||||
focalPlane.CFrame = cf
|
||||
waterPlane.CFrame = cf
|
||||
else
|
||||
waterPlane.Parent = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Util.Raycast(pos: Vector3, dir: Vector3, maybeParams: RaycastParams?, worldRoot: WorldRoot?): RaycastResult?
|
||||
local root = worldRoot or workspace
|
||||
local params = maybeParams or rayParams
|
||||
|
@ -96,8 +132,9 @@ function Util.Raycast(pos: Vector3, dir: Vector3, maybeParams: RaycastParams?, w
|
|||
return result
|
||||
end
|
||||
|
||||
function Util.RaycastSM64(pos: Vector3, dir: Vector3, rayParams: RaycastParams?, worldRoot: WorldRoot?): RaycastResult?
|
||||
local result: RaycastResult? = Util.Raycast(pos * Util.Scale, dir * Util.Scale, rayParams, worldRoot)
|
||||
-- stylua: ignore
|
||||
function Util.RaycastSM64(pos: Vector3, dir: Vector3, maybeParams: RaycastParams?, worldRoot: WorldRoot?): RaycastResult?
|
||||
local result: RaycastResult? = Util.Raycast(pos * Util.Scale, dir * Util.Scale, maybeParams or rayParams, worldRoot)
|
||||
|
||||
if result then
|
||||
-- Cast back to SM64 unit scale.
|
||||
|
@ -131,7 +168,7 @@ function Util.FindFloor(pos: Vector3): (number, RaycastResult?)
|
|||
newPos = Vector3.new(trunc.X, trunc.Y, trunc.Z)
|
||||
end
|
||||
|
||||
local result = Util.RaycastSM64(newPos + (Vector3.yAxis * 100), -Vector3.yAxis * 10000)
|
||||
local result = Util.RaycastSM64(newPos + (Vector3.yAxis * 100), -Vector3.yAxis * 10000, rayParams)
|
||||
|
||||
if result then
|
||||
height = Util.SignedShort(result.Position.Y)
|
||||
|
@ -159,7 +196,7 @@ function Util.FindCeil(pos: Vector3, height: number?): (number, RaycastResult?)
|
|||
end
|
||||
|
||||
local head = Vector3.new(pos.X, (height or pos.Y) + 80, pos.Z)
|
||||
local result = Util.RaycastSM64(head, Vector3.yAxis * 10000)
|
||||
local result = Util.RaycastSM64(head, Vector3.yAxis * 10000, rayParams)
|
||||
|
||||
if result then
|
||||
newHeight = result.Position.Y
|
||||
|
|
|
@ -37,10 +37,11 @@ type Controller = Types.Controller
|
|||
type Mario = Mario.Class
|
||||
|
||||
local player: Player = assert(Players.LocalPlayer)
|
||||
local FLIP = CFrame.Angles(0, math.pi, 0)
|
||||
local mario: Mario = Mario.new()
|
||||
|
||||
local STEP_RATE = 30
|
||||
local NULL_TEXT = `<font color="#FF0000">NULL</font>`
|
||||
local FLIP = CFrame.Angles(0, math.pi, 0)
|
||||
|
||||
local debugStats = Instance.new("BoolValue")
|
||||
debugStats.Name = "DebugStats"
|
||||
|
@ -70,6 +71,7 @@ local AUTO_STATS = {
|
|||
|
||||
"CeilHeight",
|
||||
"FloorHeight",
|
||||
"WaterLevel",
|
||||
}
|
||||
|
||||
local ControlModule: {
|
||||
|
@ -213,8 +215,10 @@ local function updateController(controller: Controller, humanoid: Humanoid?)
|
|||
|
||||
local character = humanoid.Parent
|
||||
if (character and character:GetAttribute("TAS")) or Core:GetAttribute("ToolAssistedInput") then
|
||||
if controller.ButtonDown:Has(Buttons.A_BUTTON) then
|
||||
controller.ButtonPressed:Set(Buttons.A_BUTTON)
|
||||
if not mario.Action:Has(Enums.ActionFlags.SWIMMING) then
|
||||
if controller.ButtonDown:Has(Buttons.A_BUTTON) then
|
||||
controller.ButtonPressed:Set(Buttons.A_BUTTON)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -268,7 +272,10 @@ function Commands.PlaySound(player: Player, name: string)
|
|||
if oldSound and oldSound:IsA("Sound") then
|
||||
canPlay = false
|
||||
|
||||
if name:sub(1, 5) == "MARIO" then
|
||||
if name:sub(1, 6) == "MOVING" or sound:GetAttribute("Decay") then
|
||||
-- Keep decaying audio alive.
|
||||
stepDecay(oldSound)
|
||||
elseif name:sub(1, 5) == "MARIO" then
|
||||
-- Restart mario sound if a 30hz interval passed.
|
||||
local now = os.clock()
|
||||
local lastPlay = oldSound:GetAttribute("LastPlay") or 0
|
||||
|
@ -277,9 +284,6 @@ function Commands.PlaySound(player: Player, name: string)
|
|||
oldSound.TimePosition = 0
|
||||
oldSound:SetAttribute("LastPlay", now)
|
||||
end
|
||||
elseif name:sub(1, 6) == "MOVING" then
|
||||
-- Keep decaying audio alive.
|
||||
stepDecay(oldSound)
|
||||
else
|
||||
-- Allow stacking.
|
||||
canPlay = true
|
||||
|
@ -322,11 +326,13 @@ function Commands.SetParticle(player: Player, name: string, set: boolean)
|
|||
elseif set ~= nil then
|
||||
particle.Enabled = set
|
||||
end
|
||||
else
|
||||
warn("particle not found:", name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Commands.SetAngle(player: Player, angle: Vector3int16)
|
||||
function Commands.SetTorsoAngle(player: Player, angle: Vector3int16)
|
||||
local character = player.Character
|
||||
local waist = character and character:FindFirstChild("Waist", true)
|
||||
|
||||
|
@ -337,6 +343,17 @@ function Commands.SetAngle(player: Player, angle: Vector3int16)
|
|||
end
|
||||
end
|
||||
|
||||
function Commands.SetHeadAngle(player: Player, angle: Vector3int16)
|
||||
local character = player.Character
|
||||
local neck = character and character:FindFirstChild("Neck", true)
|
||||
|
||||
if neck and neck:IsA("Motor6D") then
|
||||
local props = { C1 = Util.ToRotation(-angle) + neck.C1.Position }
|
||||
local tween = TweenService:Create(neck, TweenInfo.new(0.1), props)
|
||||
tween:Play()
|
||||
end
|
||||
end
|
||||
|
||||
function Commands.SetCamera(player: Player, cf: CFrame?)
|
||||
local camera = workspace.CurrentCamera
|
||||
|
||||
|
@ -376,8 +393,8 @@ lazyNetwork.OnClientEvent:Connect(onNetworkReceive)
|
|||
-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local lastUpdate = os.clock()
|
||||
local lastAngle: Vector3int16?
|
||||
local mario: Mario = Mario.new()
|
||||
local lastHeadAngle: Vector3int16?
|
||||
local lastTorsoAngle: Vector3int16?
|
||||
|
||||
local activeScale = 1
|
||||
local subframe = 0 -- 30hz subframe
|
||||
|
@ -452,6 +469,30 @@ local function onReset()
|
|||
mario:SetAction(Action.SPAWN_SPIN_AIRBORNE)
|
||||
end
|
||||
|
||||
local function getWaterLevel(pos: Vector3)
|
||||
local terrain = workspace.Terrain
|
||||
local voxelPos = terrain:WorldToCellPreferSolid(pos)
|
||||
|
||||
local voxelRegion = Region3.new(voxelPos * 4, (voxelPos + Vector3.one + (Vector3.yAxis * 3)) * 4)
|
||||
voxelRegion = voxelRegion:ExpandToGrid(4)
|
||||
|
||||
local materials, occupancies = terrain:ReadVoxels(voxelRegion, 4)
|
||||
local size: Vector3 = occupancies.Size
|
||||
local waterLevel = -11000
|
||||
|
||||
for y = 1, size.Y do
|
||||
local occupancy = occupancies[1][y][1]
|
||||
local material = materials[1][y][1]
|
||||
|
||||
if occupancy >= 0.9 and material == Enum.Material.Water then
|
||||
local top = ((voxelPos.Y * 4) + (4 * y + 2))
|
||||
waterLevel = math.max(waterLevel, top / Util.Scale)
|
||||
end
|
||||
end
|
||||
|
||||
return waterLevel
|
||||
end
|
||||
|
||||
local function update()
|
||||
local character = player.Character
|
||||
|
||||
|
@ -474,18 +515,20 @@ local function update()
|
|||
-- Disabled for now because this causes parallel universes to break.
|
||||
-- TODO: Find a better way to do two-way syncing between these values.
|
||||
|
||||
--[[
|
||||
local pos = character:GetPivot().Position
|
||||
local dist = (Util.ToRoblox(mario.Position) - pos).Magnitude
|
||||
-- local pos = character:GetPivot().Position
|
||||
-- local dist = (Util.ToRoblox(mario.Position) - pos).Magnitude
|
||||
|
||||
if dist > (scale * 20) then
|
||||
mario.Position = Util.ToSM64(pos)
|
||||
end
|
||||
]]
|
||||
-- if dist > (scale * 20) then
|
||||
-- mario.Position = Util.ToSM64(pos)
|
||||
-- end
|
||||
|
||||
local humanoid = character:FindFirstChildOfClass("Humanoid")
|
||||
local simSpeed = tonumber(character:GetAttribute("TimeScale") or nil) or 1
|
||||
|
||||
local robloxPos = Util.ToRoblox(mario.Position)
|
||||
mario.WaterLevel = getWaterLevel(robloxPos)
|
||||
Util.DebugWater(mario.WaterLevel)
|
||||
|
||||
subframe += (now - lastUpdate) * (STEP_RATE * simSpeed)
|
||||
lastUpdate = now
|
||||
|
||||
|
@ -632,15 +675,21 @@ local function update()
|
|||
end
|
||||
|
||||
local bodyState = mario.BodyState
|
||||
local ang = bodyState.TorsoAngle
|
||||
local headAngle = bodyState.HeadAngle
|
||||
local torsoAngle = bodyState.TorsoAngle
|
||||
|
||||
if actionId ~= Action.BUTT_SLIDE and actionId ~= Action.WALKING then
|
||||
bodyState.TorsoAngle *= 0
|
||||
end
|
||||
|
||||
if ang ~= lastAngle then
|
||||
networkDispatch("SetAngle", ang)
|
||||
lastAngle = ang
|
||||
if torsoAngle ~= lastTorsoAngle then
|
||||
networkDispatch("SetTorsoAngle", torsoAngle)
|
||||
lastTorsoAngle = torsoAngle
|
||||
end
|
||||
|
||||
if headAngle ~= lastHeadAngle then
|
||||
networkDispatch("SetHeadAngle", headAngle)
|
||||
lastHeadAngle = headAngle
|
||||
end
|
||||
|
||||
if particles then
|
||||
|
@ -652,6 +701,10 @@ local function update()
|
|||
local emit = particle:GetAttribute("Emit")
|
||||
local hasFlag = mario.ParticleFlags:Has(flag)
|
||||
|
||||
if hasFlag then
|
||||
print("SetParticle", name)
|
||||
end
|
||||
|
||||
if emit then
|
||||
if hasFlag then
|
||||
networkDispatch("SetParticle", name)
|
||||
|
|
|
@ -43,7 +43,11 @@ function Validators.SetParticle(player: Player, name: string, set: boolean?)
|
|||
return false
|
||||
end
|
||||
|
||||
function Validators.SetAngle(player: Player, angle: Vector3int16)
|
||||
function Validators.SetTorsoAngle(player: Player, angle: Vector3int16)
|
||||
return typeof(angle) == "Vector3int16"
|
||||
end
|
||||
|
||||
function Validators.SetHeadAngle(player: Player, angle: Vector3int16)
|
||||
return typeof(angle) == "Vector3int16"
|
||||
end
|
||||
|
||||
|
|
|
@ -181,6 +181,35 @@
|
|||
<NumberSequence name="Transparency">0 1 0 0.1 0.75 0 0.5 0.75 0 1 1 0 </NumberSequence>
|
||||
</Properties>
|
||||
</Item>
|
||||
<Item class="ParticleEmitter" referent="RBX16">
|
||||
<Properties>
|
||||
<Vector3 name="Acceleration">
|
||||
<X>0</X>
|
||||
<Y>-1</Y>
|
||||
<Z>0</Z>
|
||||
</Vector3>
|
||||
<BinaryString name="AttributesSerialize">AQAAAAQAAABFbWl0BgAAAAAAADlA</BinaryString>
|
||||
<ColorSequence name="Color">0 0.807843 0.807843 0.807843 0 1 0.807843 0.807843 0.807843 0 </ColorSequence>
|
||||
<float name="Drag">3</float>
|
||||
<token name="EmissionDirection">5</token>
|
||||
<bool name="Enabled">false</bool>
|
||||
<NumberRange name="Lifetime">2 2 </NumberRange>
|
||||
<float name="LightEmission">1</float>
|
||||
<float name="LightInfluence">1</float>
|
||||
<string name="Name">PLUNGE_BUBBLE</string>
|
||||
<float name="Rate">100</float>
|
||||
<NumberRange name="RotSpeed">-360 360 </NumberRange>
|
||||
<NumberRange name="Rotation">0 360 </NumberRange>
|
||||
<NumberSequence name="Size">0 2 0 1 2 0 </NumberSequence>
|
||||
<NumberRange name="Speed">20 20 </NumberRange>
|
||||
<Vector2 name="SpreadAngle">
|
||||
<X>360</X>
|
||||
<Y>360</Y>
|
||||
</Vector2>
|
||||
<Content name="Texture"><url>rbxassetid://425366688</url></Content>
|
||||
<NumberSequence name="Transparency">0 1 0 0.1 0.75 0 0.5 0.75 0 1 1 0 </NumberSequence>
|
||||
</Properties>
|
||||
</Item>
|
||||
<Item class="Vector3Value" referent="RBX10">
|
||||
<Properties>
|
||||
<string name="Name">OriginalPosition</string>
|
||||
|
|
|
@ -637,7 +637,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101766690"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
@ -787,11 +787,11 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101764246"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
"Loop": false,
|
||||
"Loop": true,
|
||||
"NumFrames": 22,
|
||||
"StartAddress": "565610"
|
||||
}
|
||||
|
@ -2517,12 +2517,12 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101761759"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
"Loop": false,
|
||||
"NumFrames": 12,
|
||||
"NumFrames": 16,
|
||||
"StartAddress": "564D2C"
|
||||
}
|
||||
},
|
||||
|
@ -2532,7 +2532,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101760003"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
@ -2862,7 +2862,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101757679"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
@ -2922,7 +2922,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101753873"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
@ -2937,7 +2937,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101755961"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
@ -2952,7 +2952,7 @@
|
|||
"className": "Animation",
|
||||
|
||||
"properties": {
|
||||
"AnimationId": ""
|
||||
"AnimationId": "rbxassetid://14101750346"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
|
|
|
@ -94,6 +94,17 @@
|
|||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_METAL_LAND_WATER",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9116519870"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_METAL_JUMP",
|
||||
"className": "Sound",
|
||||
|
@ -104,6 +115,17 @@
|
|||
"SoundId": "rbxassetid://9116519870"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_METAL_JUMP_WATER",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9116519870"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_METAL_STEP",
|
||||
|
@ -148,6 +170,48 @@
|
|||
"SoundId": "rbxassetid://6552141879"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_SWIM_KICK",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9117823333",
|
||||
"Volume": 0.05
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_SWIM_FAST",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9117822492",
|
||||
"Volume": 0.1,
|
||||
|
||||
"PlaybackRegion": {
|
||||
"NumberRange": [1, 2.5]
|
||||
},
|
||||
|
||||
"PlaybackRegionsEnabled": true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_SWIM",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9120554658",
|
||||
"Volume": 0.5
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_TERRAIN_BODY_HIT_GROUND",
|
||||
|
@ -405,6 +469,38 @@
|
|||
"SoundId": ""
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_WATER_ENTER",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxassetid://9117822587",
|
||||
|
||||
"PlaybackRegion": {
|
||||
"NumberRange": [0, 4]
|
||||
},
|
||||
|
||||
"PlaybackRegionsEnabled": true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ACTION_WATER_EXIT",
|
||||
"className": "Sound",
|
||||
|
||||
"properties": {
|
||||
"RollOffMinDistance": 8,
|
||||
"RollOffMaxDistance": 128,
|
||||
"SoundId": "rbxasset://sounds/impact_water.mp3"
|
||||
},
|
||||
|
||||
"attributes": {
|
||||
"Decay": true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "MARIO_ATTACKED",
|
||||
|
|
|
@ -234,6 +234,14 @@ local SoundTable = {
|
|||
ACTION_THROW = Sounds.ACTION_THROW,
|
||||
ACTION_TWIRL = Sounds.ACTION_TWIRL,
|
||||
|
||||
ACTION_METAL_LAND_WATER = Sounds.ACTION_METAL_LAND_WATER,
|
||||
ACTION_METAL_JUMP_WATER = Sounds.ACTION_METAL_LAND_WATER,
|
||||
ACTION_WATER_ENTER = Sounds.ACTION_WATER_ENTER,
|
||||
ACTION_WATER_EXIT = Sounds.ACTION_WATER_EXIT,
|
||||
ACTION_SWIM_KICK = Sounds.ACTION_SWIM_KICK,
|
||||
ACTION_SWIM_FAST = Sounds.ACTION_SWIM_FAST,
|
||||
ACTION_SWIM = Sounds.ACTION_SWIM,
|
||||
|
||||
MARIO_ATTACKED = Sounds.MARIO_ATTACKED,
|
||||
MARIO_DOH = Sounds.MARIO_DOH,
|
||||
MARIO_GROUND_POUND_WAH = Sounds.MARIO_GROUND_POUND_WAH,
|
||||
|
|
Loading…
Reference in a new issue