--!strict local Core = script.Parent if Core:GetAttribute("HotLoading") then task.wait(3) end for i, desc in script:GetDescendants() do if desc:IsA("BaseScript") then desc.Enabled = true end end local Players = game:GetService("Players") local RunService = game:GetService("RunService") local StarterGui = game:GetService("StarterGui") local TweenService = game:GetService("TweenService") local UserInputService = game:GetService("UserInputService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local ContextActionService = game:GetService("ContextActionService") local Shared = require(Core.Shared) local Sounds = Shared.Sounds local Enums = require(script.Enums) local Mario = require(script.Mario) local Types = require(script.Types) local Util = require(script.Util) local Action = Enums.Action local Buttons = Enums.Buttons local MarioFlags = Enums.MarioFlags local ParticleFlags = Enums.ParticleFlags type InputType = Enum.UserInputType | Enum.KeyCode type Controller = Types.Controller type Mario = Mario.Class local player: Player = assert(Players.LocalPlayer) local mario: Mario = Mario.new() local STEP_RATE = 30 local NULL_TEXT = `NULL` local FLIP = CFrame.Angles(0, math.pi, 0) local debugStats = Instance.new("BoolValue") debugStats.Name = "DebugStats" debugStats.Archivable = false debugStats.Parent = game local PARTICLE_CLASSES = { Fire = true, Smoke = true, Sparkles = true, ParticleEmitter = true, } local AUTO_STATS = { "Position", "Velocity", "AnimFrame", "FaceAngle", "ActionState", "ActionTimer", "ActionArg", "ForwardVel", "SlideVelX", "SlideVelZ", "CeilHeight", "FloorHeight", "WaterLevel", } local ControlModule: { GetMoveVector: (self: any) -> Vector3, } while not ControlModule do local inst = player:FindFirstChild("ControlModule", true) if inst then ControlModule = (require :: any)(inst) end task.wait(0.1) end ------------------------------------------------------------------------------------------------------------------------------------------------- -- Input Driver ------------------------------------------------------------------------------------------------------------------------------------------------- -- NOTE: I had to replace the default BindAction via KeyCode and UserInputType -- BindAction forces some mappings (such as R2 mapping to MouseButton1) which you -- can't turn off otherwise. local BUTTON_FEED = {} local BUTTON_BINDS = {} local function toStrictNumber(str: string): number local result = tonumber(str) return assert(result, "Invalid number!") end local function processAction(id: string, state: Enum.UserInputState, input: InputObject) if id == "MarioDebug" and Core:GetAttribute("DebugToggle") then if state == Enum.UserInputState.Begin then local character = player.Character if character then local isDebug = not character:GetAttribute("Debug") character:SetAttribute("Debug", isDebug) end end else local button = toStrictNumber(id:sub(5)) BUTTON_FEED[button] = state end end local function processInput(input: InputObject, gameProcessedEvent: boolean) if gameProcessedEvent then return end if BUTTON_BINDS[input.UserInputType] ~= nil then processAction(BUTTON_BINDS[input.UserInputType], input.UserInputState, input) end if BUTTON_BINDS[input.KeyCode] ~= nil then processAction(BUTTON_BINDS[input.KeyCode], input.UserInputState, input) end end UserInputService.InputBegan:Connect(processInput) UserInputService.InputChanged:Connect(processInput) UserInputService.InputEnded:Connect(processInput) local function bindInput(button: number, label: string, ...: InputType) local id = "BTN_" .. button if UserInputService.TouchEnabled then ContextActionService:BindAction(id, processAction, true) ContextActionService:SetTitle(id, label) end for i, input in { ... } do BUTTON_BINDS[input] = id end end local function updateCollisions() for i, player in Players:GetPlayers() do -- stylua: ignore local character = player.Character local rootPart = character and character.PrimaryPart if rootPart then local parts = rootPart:GetConnectedParts(true) for i, part in parts do if part:IsA("BasePart") then part.CanCollide = false end end end end end local function updateController(controller: Controller, humanoid: Humanoid?) if not humanoid then return end local moveDir = ControlModule:GetMoveVector() local pos = Vector2.new(moveDir.X, -moveDir.Z) local mag = 0 if pos.Magnitude > 0 then if pos.Magnitude > 1 then pos = pos.Unit end mag = pos.Magnitude end controller.StickMag = mag * 64 controller.StickX = pos.X * 64 controller.StickY = pos.Y * 64 humanoid:ChangeState(Enum.HumanoidStateType.Physics) controller.ButtonPressed:Clear() if humanoid.Jump then BUTTON_FEED[Buttons.A_BUTTON] = Enum.UserInputState.Begin elseif controller.ButtonDown:Has(Buttons.A_BUTTON) then BUTTON_FEED[Buttons.A_BUTTON] = Enum.UserInputState.End end local lastButtonValue = controller.ButtonDown() for button, state in pairs(BUTTON_FEED) do if state == Enum.UserInputState.Begin then controller.ButtonDown:Add(button) elseif state == Enum.UserInputState.End then controller.ButtonDown:Remove(button) end end table.clear(BUTTON_FEED) local buttonValue = controller.ButtonDown() controller.ButtonPressed:Set(buttonValue) controller.ButtonPressed:Band(bit32.bxor(buttonValue, lastButtonValue)) local character = humanoid.Parent if (character and character:GetAttribute("TAS")) or Core:GetAttribute("ToolAssistedInput") then 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 ContextActionService:BindAction("MarioDebug", processAction, false, Enum.KeyCode.P) bindInput(Buttons.B_BUTTON, "B", Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonX) bindInput( Buttons.Z_TRIG, "Z", Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift, Enum.KeyCode.ButtonL2, Enum.KeyCode.ButtonR2 ) ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Network Dispatch ------------------------------------------------------------------------------------------------------------------------------------------------------------- local Commands = {} local soundDecay = {} local lazyNetwork = ReplicatedStorage:WaitForChild("LazyNetwork") assert(lazyNetwork:IsA("RemoteEvent"), "bad lazyNetwork!") local function stepDecay(sound: Sound) local decay = soundDecay[sound] if decay then task.cancel(decay) end soundDecay[sound] = task.delay(0.1, function() sound:Stop() sound:Destroy() soundDecay[sound] = nil end) sound.Playing = true end function Commands.PlaySound(player: Player, name: string) local sound: Sound? = Sounds[name] local character = player.Character local rootPart = character and character.PrimaryPart if rootPart and sound then local oldSound: Instance? = rootPart:FindFirstChild(name) local canPlay = true if oldSound and oldSound:IsA("Sound") then canPlay = false 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 if now - lastPlay >= 2 / STEP_RATE then oldSound.TimePosition = 0 oldSound:SetAttribute("LastPlay", now) end else -- Allow stacking. canPlay = true end end if canPlay then local newSound: Sound = sound:Clone() newSound.Parent = rootPart newSound:Play() if name:find("MOVING") then -- Audio will decay if PlaySound isn't continuously called. stepDecay(newSound) end newSound.Ended:Connect(function() newSound:Destroy() end) newSound:SetAttribute("LastPlay", os.clock()) end end end function Commands.SetParticle(player: Player, name: string, set: boolean) local character = player.Character local rootPart = character and character.PrimaryPart if rootPart then local particles = rootPart:FindFirstChild("Particles") local inst = particles and particles:FindFirstChild(name, true) if inst and PARTICLE_CLASSES[inst.ClassName] then local particle = inst :: ParticleEmitter local emit = particle:GetAttribute("Emit") if typeof(emit) == "number" then particle:Emit(emit) elseif set ~= nil then particle.Enabled = set end else warn("particle not found:", name) end end end function Commands.SetTorsoAngle(player: Player, angle: Vector3int16) local character = player.Character local waist = character and character:FindFirstChild("Waist", true) if waist and waist:IsA("Motor6D") then local props = { C1 = Util.ToRotation(-angle) + waist.C1.Position } local tween = TweenService:Create(waist, TweenInfo.new(0.1), props) tween:Play() 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 if cf ~= nil then camera.CameraType = Enum.CameraType.Scriptable camera.CFrame = cf else camera.CameraType = Enum.CameraType.Custom end end local function processCommand(player: Player, cmd: string, ...: any) local command = Commands[cmd] if command then task.spawn(command, player, ...) else warn("Unknown Command:", cmd, ...) end end local function networkDispatch(cmd: string, ...: any) lazyNetwork:FireServer(cmd, ...) processCommand(player, cmd, ...) end local function onNetworkReceive(target: Player, cmd: string, ...: any) if target ~= player then processCommand(target, cmd, ...) end end lazyNetwork.OnClientEvent:Connect(onNetworkReceive) ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Mario Driver ------------------------------------------------------------------------------------------------------------------------------------------------------------- local lastUpdate = os.clock() local lastHeadAngle: Vector3int16? local lastTorsoAngle: Vector3int16? local activeScale = 1 local subframe = 0 -- 30hz subframe local emptyId = "" local goalCF: CFrame local prevCF: CFrame local activeTrack: AnimationTrack? local reset = Instance.new("BindableEvent") reset.Archivable = false reset.Parent = script reset.Name = "Reset" if RunService:IsStudio() then local dummySequence = Instance.new("KeyframeSequence") local provider = game:GetService("KeyframeSequenceProvider") emptyId = provider:RegisterKeyframeSequence(dummySequence) end while not player.Character do player.CharacterAdded:Wait() end local character = assert(player.Character) local pivot = character:GetPivot() mario.Position = Util.ToSM64(pivot.Position) goalCF = pivot prevCF = pivot local function setDebugStat(key: string, value: any) if typeof(value) == "Vector3" then value = string.format("%.3f, %.3f, %.3f", value.X, value.Y, value.Z) elseif typeof(value) == "Vector3int16" then value = string.format("%i, %i, %i", value.X, value.Y, value.Z) elseif type(value) == "number" then value = string.format("%.3f", value) end debugStats:SetAttribute(key, value) end --THIS IS WHERE THE SPAWNLOCATION IMPLEMENTATION IS local function getTeamSpawnPosition(player) local teamColor = player.TeamColor local spawnLocations = game.Workspace:GetDescendants() local teamSpawn = nil -- Find a spawn location with the same TeamColor as the player's team for _, spawn in pairs(spawnLocations) do if spawn.ClassName == "SpawnLocation" then if spawn.TeamColor == teamColor then teamSpawn = spawn break end end end if teamSpawn then return teamSpawn.Position else warn("No spawn location found for team color: " .. tostring(teamColor)) return game.workspace:FindFirstChild("SpawnLocation") --default end end local function onReset() local roblox = getTeamSpawnPosition(player) --THIS IS WHERE THE SPAWNLOCATION IMPLEMENTATION IS CALLED local sm64 = Util.ToSM64(roblox) local char = player.Character if char then local reset = char:FindFirstChild("Reset") local cf = CFrame.new(roblox) goalCF = cf prevCF = cf if reset and reset:IsA("RemoteEvent") then reset:FireServer() end end mario.SlideVelX = 0 mario.SlideVelZ = 0 mario.ForwardVel = 0 mario.IntendedYaw = 0 mario.Position = sm64 mario.Velocity = Vector3.zero mario.FaceAngle = Vector3int16.new() 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 if not character then return end local now = os.clock() local gfxRot = CFrame.identity local scale = character:GetScale() if scale ~= activeScale then local marioPos = Util.ToRoblox(mario.Position) Util.Scale = scale / 20 -- HACK! Should this be instanced? mario.Position = Util.ToSM64(marioPos) activeScale = scale end -- 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 -- 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 if character:GetAttribute("WingCap") or Core:GetAttribute("WingCap") then mario.Flags:Add(MarioFlags.WING_CAP) else mario.Flags:Remove(MarioFlags.WING_CAP) end if character:GetAttribute("Metal") then mario.Flags:Add(MarioFlags.METAL_CAP) else mario.Flags:Remove(MarioFlags.METAL_CAP) end subframe = math.min(subframe, 4) -- Prevent execution runoff while subframe >= 1 do subframe -= 1 updateCollisions() updateController(mario.Controller, humanoid) mario:ExecuteAction() local gfxPos = Util.ToRoblox(mario.Position) gfxRot = Util.ToRotation(mario.GfxAngle) prevCF = goalCF goalCF = CFrame.new(gfxPos) * FLIP * gfxRot end if character and goalCF then local cf = character:GetPivot() local rootPart = character.PrimaryPart local animator = character:FindFirstChildWhichIsA("Animator", true) if animator and (mario.AnimDirty or mario.AnimReset) and mario.AnimFrame >= 0 then local anim = mario.AnimCurrent local animSpeed = 0.1 / simSpeed if activeTrack and (activeTrack.Animation ~= anim or mario.AnimReset) then if tostring(activeTrack.Animation) == "TURNING_PART1" then if anim and anim.Name == "TURNING_PART2" then mario.AnimSkipInterp = 2 animSpeed *= 2 end end activeTrack:Stop(animSpeed) activeTrack = nil end if not activeTrack and anim then if anim.AnimationId == "" then if RunService:IsStudio() then warn("!! FIXME: Empty AnimationId for", anim.Name, "will break in live games!") end anim.AnimationId = emptyId end local track = animator:LoadAnimation(anim) track:Play(animSpeed, 1, 0) activeTrack = track end if activeTrack then local speed = mario.AnimAccel / 0x10000 if speed > 0 then activeTrack:AdjustSpeed(speed * simSpeed) else activeTrack:AdjustSpeed(simSpeed) end end mario.AnimDirty = false mario.AnimReset = false end if activeTrack and mario.AnimSetFrame > -1 then activeTrack.TimePosition = mario.AnimSetFrame / STEP_RATE mario.AnimSetFrame = -1 end if rootPart then local particles = rootPart:FindFirstChild("Particles") local alignPos = rootPart:FindFirstChildOfClass("AlignPosition") local alignCF = rootPart:FindFirstChildOfClass("AlignOrientation") local actionId = mario.Action() local throw = mario.ThrowMatrix if throw then local throwPos = Util.ToRoblox(throw.Position) goalCF = throw.Rotation * FLIP + throwPos end if alignCF then local nextCF = prevCF:Lerp(goalCF, subframe) -- stylua: ignore cf = if mario.AnimSkipInterp > 0 then cf.Rotation + nextCF.Position else nextCF alignCF.CFrame = cf.Rotation end local isDebug = character:GetAttribute("Debug") local limits = character:GetAttribute("EmulateLimits") script.Util:SetAttribute("Debug", isDebug) debugStats.Value = isDebug if limits ~= nil then Core:SetAttribute("TruncateBounds", limits) end if isDebug then local animName = activeTrack and tostring(activeTrack.Animation) setDebugStat("Animation", animName) local actionName = Enums.GetName(Action, actionId) setDebugStat("Action", actionName) local wall = mario.Wall setDebugStat("Wall", wall and wall.Instance.Name or NULL_TEXT) local floor = mario.Floor setDebugStat("Floor", floor and floor.Instance.Name or NULL_TEXT) local ceil = mario.Ceil setDebugStat("Ceiling", ceil and ceil.Instance.Name or NULL_TEXT) end for _, name in AUTO_STATS do local value = rawget(mario :: any, name) setDebugStat(name, value) end if alignPos then alignPos.Position = cf.Position end local bodyState = mario.BodyState local headAngle = bodyState.HeadAngle local torsoAngle = bodyState.TorsoAngle if actionId ~= Action.BUTT_SLIDE and actionId ~= Action.WALKING then bodyState.TorsoAngle *= 0 end if torsoAngle ~= lastTorsoAngle then networkDispatch("SetTorsoAngle", torsoAngle) lastTorsoAngle = torsoAngle end if headAngle ~= lastHeadAngle then networkDispatch("SetHeadAngle", headAngle) lastHeadAngle = headAngle end if particles then for name, flag in pairs(ParticleFlags) do local inst = particles:FindFirstChild(name, true) if inst and PARTICLE_CLASSES[inst.ClassName] then local particle = inst :: ParticleEmitter 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) end elseif particle.Enabled ~= hasFlag then networkDispatch("SetParticle", name, hasFlag) end end end end for name: string, sound: Sound in pairs(Sounds) do local looped = false if sound:IsA("Sound") then if sound.TimeLength == 0 then continue end looped = sound.Looped end if sound:GetAttribute("Play") then networkDispatch("PlaySound", sound.Name) if not looped then sound:SetAttribute("Play", false) end elseif looped then sound:Stop() end end character:PivotTo(cf) end end end reset.Event:Connect(onReset) RunService.Heartbeat:Connect(update) while task.wait(1) do local success = pcall(function() return StarterGui:SetCore("ResetButtonCallback", reset) end) if success then break end end -------------------------------------------------------------------------------------------------------------------------------------------------------------