Roblox/luau_corpus huggingface dataset:
--[[Weld functions]]

	local JS = game:GetService("JointsService")
	local PGS_ON = workspace:PGSIsEnabled()
	
	function MakeWeld(x,y,type,s) 
		if type==nil then type="Weld" end
		local W=Instance.new(type,JS) 
		W.Part0=x W.Part1=y 
		W.C0=x.CFrame:inverse()*x.CFrame 
		W.C1=y.CFrame:inverse()*x.CFrame 
		if type=="Motor" and s~=nil then 
			W.MaxVelocity=s 
		end 
		return W	
	end
	
	function ModelWeld(a,b) 
		if a:IsA("BasePart") and 
			a.Parent.Name ~= ("Lights") then
			MakeWeld(b,a,"Weld") 
		elseif a:IsA("Model") then 
			for i,v in pairs(a:GetChildren()) do 
				ModelWeld(v,b) 
			end 
		end 
	end
	
	function UnAnchor(a) 
		if a:IsA("BasePart") then a.Anchored=false  end for i,v in pairs(a:GetChildren()) do UnAnchor(v) end 
	end
--[=[
	Returns a resolved promise with the following values

	@param ... Values to resolve to
	@return Promise<T>
]=]
function Promise.resolved(...)
	local n = select("#", ...)
	if n == 0 then
		-- Reuse promise here to save on calls to Promise.resolved()
		return _emptyFulfilledPromise
	elseif n == 1 and Promise.isPromise(...) then
		local promise = (...)

		-- Resolving to promise that is already resolved. Just return the promise!
		if not promise._pendingExecuteList then
			return promise
		end
	end

	local promise = Promise.new()
	promise:Resolve(...)
	return promise
end
--[[
		___      _______                _     
	   / _ |____/ ___/ /  ___ ____ ___ (_)__ 
	  / __ /___/ /__/ _ \/ _ `(_-<(_-</ (_-<
	 /_/ |_|   \___/_//_/\_,_/___/___/_/___/
 						SecondLogic @ Inspare
]]


local autoscaling	= false					--Estimates top speed

local UNITS	= {								--Click on speed to change units
											--First unit is default	
												{
		units			= "KM/H"			,
		scaling			= (10/12) * 1.09728	, -- 1 stud : 10 inches | ft/s to KP/H
		maxSpeed		= 260				,
		spInc			= 40				, -- Increment between labelled notches
	},
	{
		units			= "MPH"				,
		scaling			= (10/12) * (60/88)	, -- 1 stud : 10 inches | ft/s to MPH
		maxSpeed		= 150				,
		spInc			= 20				, -- Increment between labelled notches
	},
	
	
	{
		units			= "SPS"				,
		scaling			= 1					, -- Roblox standard
		maxSpeed		= 400				,
		spInc			= 40				, -- Increment between labelled notches
	}
}
--!strict
-- upstream: https://github.com/facebook/react/blob/702fad4b1b48ac8f626ed3f35e8f86f5ea728084/packages/shared/invokeGuardedCallbackImpl.js
--[[*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 ]]
-- local invariant = require(script.Parent.invariant)
local describeError = require(script.Parent["ErrorHandling.roblox"]).describeError
-- Fonction pour trouver la source d'eau la plus proche
local function findNearestWaterSource(position)
	local nearestWaterSource = nil
	local nearestDistance = math.huge

	-- Parcours de toutes les cellules du terrain
	for x = 0, terrain.Size.X, terrain.Resolution do
		for y = 0, terrain.Size.Y, terrain.Resolution do
			local cellPosition = Vector3.new(x, 0, y)

			-- Vérifie si la cellule est de l'eau
			if terrain:GetMaterial(cellPosition) == Enum.Material.Water then
				-- Calcule la distance entre la cellule d'eau et la position actuelle
				local distance = calculateDistance(position, cellPosition)

				-- Vérifie si c'est la source d'eau la plus proche jusqu'à présent
				if distance < nearestDistance then
					nearestDistance = distance
					nearestWaterSource = cellPosition
				end
			end
		end
	end

	return nearestWaterSource
end
--[[Drivetrain]]	
	Tune.Config			= "AWD"		--"FWD" , "RWD" , "AWD"
	
	--Differential Settings	
	Tune.FDiffSlipThres	= 0		-- 1 - 100%				(Max threshold of applying full lock determined by deviation from avg speed)
	Tune.FDiffLockThres	= 0			-- 0 - 100%				(0 - Bias toward slower wheel, 100 - Bias toward faster wheel)
	Tune.RDiffSlipThres	= 0		-- 1 - 100%
	Tune.RDiffLockThres	= 0			-- 0 - 100%
	Tune.CDiffSlipThres	= 0			-- 1 - 100%				[AWD Only]
	Tune.CDiffLockThres	= 0			-- 0 - 100%				[AWD Only]
	
	--Traction Control Settings
	Tune.TCSEnabled		= false		-- Implements TCS
	Tune.TCSThreshold	= 20		-- Slip speed allowed before TCS starts working (in SPS)
	Tune.TCSGradient	= 20		-- Slip speed gradient between 0 to max reduction (in SPS)
	Tune.TCSLimit		= 20		-- Minimum amount of torque at max reduction (in percent)
--> FUNCTIONS
local function ButtonPress(Button)
	local Sound = script.Click:Clone()
	Sound.Parent = Button
	Sound:Play()
	Button.Size = Vector3.new(0.8, 0.8, .01)
	wait(.2)
	Button.Size = Vector3.new(0.8, 0.8, 0.1)
	Sound:Destroy()
end

local function Clear()
	Text.Text = ""
	EnteredText.Value = Text.Text
end

for i, v in pairs(Board:WaitForChild("Numbers"):getChildren()) do
	v.ClickDetector.MouseClick:Connect(function()
		ButtonPress(v)
		if string.len(Text.Text) < string.len(Code) then
			Text.Text = Text.Text..v.Name
			EnteredText.Value = Text.Text
		else
			Text.Text = v.Name
			EnteredText.Value = Text.Text
		end
	end)
end

OtherButtons.Enter.ClickDetector.MouseClick:Connect(function()
	ButtonPress(OtherButtons.Enter)
	if EnteredText.Value == Code then
		OtherButtons.Enter.Approved:Play()
		Clear()
		for count = 1, 10 do
			Door.Door.Transparency = Door.Door.Transparency + .1
			wait()
		end
		Door.Door.CanCollide = false
		wait(3)
		Door.Door.CanCollide = true
		for count = 1, 10 do
			Door.Door.Transparency = Door.Door.Transparency - .1
			wait()
		end
	else
		OtherButtons.Enter.Denied:Play()
		Clear()
	end
end)

OtherButtons.Clear.ClickDetector.MouseClick:Connect(function()
	ButtonPress(OtherButtons.Clear)
	Clear()
end)
--[=[
	Hides the pane
	@param doNotAnimate boolean? -- True if this visiblity should not animate
]=]
function BasicPane:Hide(doNotAnimate)
	self:SetVisible(false, doNotAnimate)
end
--//Controller//--
Holder.ChildAdded:Connect(function(Donation)
	if Donation:IsA("Frame") then
		local Button = Donation.Button

		Button.MouseButton1Click:Connect(function()
			local ProductInfo = MPS:PromptProductPurchase(Player, Button:GetAttribute("ID"))

		end)
	end
end)
--		print(animName .. " " .. idx .. " [" .. origRoll .. "]")
		local anim = animTable[animName][idx].anim

		-- load it to the humanoid; get AnimationTrack
		currentAnimTrack = humanoid:LoadAnimation(anim)

		-- play the animation
		currentAnimTrack:Play(transitionTime)
		currentAnim = animName

		-- set up keyframe name triggers
		if (currentAnimKeyframeHandler ~= nil) then
			currentAnimKeyframeHandler:disconnect()
		end
		currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
	end
end
--create tables:
for i,part in pairs(model:GetChildren()) do
	if (string.sub(part.Name, 1,1) == "a" or string.sub(part.Name, 1,1) == "c") and part:IsA("BasePart") then
		table.insert(a, 1, part)
	end
end
for i,part in pairs(model:GetChildren()) do
	if (string.sub(part.Name, 1,1) == "b" or string.sub(part.Name, 1,1) == "c") and part:IsA("BasePart") then
		table.insert(b, 1, part)
	end
end

function lightOn(T)
	for i, part in pairs (T) do
		part.SurfaceLight.Enabled = true
		if part:FindFirstChild("SpotLight") then 
			part.SpotLight.Enabled = true
		end
	end
end

function lightOff(T)
	for i, part in pairs (T) do
		part.SurfaceLight.Enabled = false
		if part:FindFirstChild("SpotLight") then
			part.SpotLight.Enabled = false
		end
	end
end

function run()
	while on do
		lightOn(a)
		wait(0.18)
	
		lightOff(a)
		wait(0.04)
	
		lightOn(a)
		wait(0.13)
	
		lightOff(a)
		wait(0.03)
		
		lightOn(b)
		wait(0.18)
	
		lightOff(b)
		wait(0.04)
		
		lightOn(b)
		wait(0.13)
	
		lightOff(b)
		wait(0.03)
	end
end

script.Parent.RemoteEvent.OnServerEvent:Connect(function()
	if on == true then
		on = false
	else
		on = true
		run()
	end
end)
--!strict
--[=[
  @function copyDeep
  @within Dictionary

  @param dictionary T -- The dictionary to copy.
  @return T -- The copied dictionary.

  Copies a dictionary recursively.

  ```lua
  local dictionary = { hello = { world = "goodbye" } }

  local new = CopyDeep(dictionary) -- { hello = { world = "goodbye" } }

  print(new == dictionary) -- false
  print(new.hello == dictionary.hello) -- false
  ```
]=]
local function copyDeep<T>(dictionary: T): T
	local new = {}

	for key, value in pairs(dictionary) do
		if type(value) == "table" then
			new[key] = copyDeep(value)
		else
			new[key] = value
		end
	end

	return new
end

return copyDeep
--This will be parented to a player

local Mouse = game:GetService("Players").LocalPlayer:GetMouse()
local Pressed = script:WaitForChild("Pressed")

Mouse.KeyDown:connect(function (Key)
	if Key == "e" then
		local Target = Mouse.Target
		Pressed:FireServer(Target)
	end
end)
--[[Susupension]]
	Tune.SusEnabled		= true		-- works only in with PGSPhysicsSolverEnabled, defaults to false when PGS is disabled
	
	--Front Suspension
	Tune.FSusDamping	= 500		-- Spring Dampening
	Tune.FSusStiffness	= 9000		-- Spring Force
	Tune.FAntiRoll 		= 50		-- Anti-Roll (Gyro Dampening)
	
	Tune.FSusLength		= 2			-- Suspension length (in studs)
	Tune.FPreCompress	= .3		-- Pre-compression adds resting length force
	Tune.FExtensionLim	= .5		-- Max Extension Travel (in studs)
	Tune.FCompressLim	= .1		-- Max Compression Travel (in studs)
	Tune.FSusAngle		= 80		-- Suspension Angle (degrees from horizontal)
		
	Tune.FWsBoneLen		= 5			-- Wishbone Length
	Tune.FWsBoneAngle	= 0			-- Wishbone angle (degrees from horizontal)
	Tune.FAnchorOffset	= {			-- Suspension anchor point offset (relative to center of wheel)
	 --[[Lateral]]		-.4		,	-- positive = outward
	 --[[Vertical]]		-.5		,	-- positive = upward
	 --[[Forward]]		0		}	-- positive = forward
	
	--Rear Suspension
	Tune.RSusDamping	= 500		-- Spring Dampening
	Tune.RSusStiffness	= 9000		-- Spring Force
	Tune.FAntiRoll 		= 50		-- Anti-Roll (Gyro Dampening)

	Tune.RSusLength		= 2.7			-- Suspension length (in studs)
	Tune.RPreCompress	= .4		-- Pre-compression adds resting length force
	Tune.RExtensionLim	= .5		-- Max Extension Travel (in studs)
	Tune.RCompressLim	= .2		-- Max Compression Travel (in studs)
	Tune.RSusAngle		= 80		-- Suspension Angle (degrees from horizontal)
		
	Tune.RWsBoneLen		= 5			-- Wishbone Length
	Tune.RWsBoneAngle	= 0			-- Wishbone angle (degrees from horizontal)
	Tune.RAnchorOffset	= {			-- Suspension anchor point offset (relative to center of wheel)
	 --[[Lateral]]		-.4		,	-- positive = outward
	 --[[Vertical]]		-.5		,	-- positive = upward
	 --[[Forward]]		0		}	-- positive = forward

	--Aesthetics	
	Tune.SusVisible		= false			-- Spring Visible
	Tune.WsBVisible		= false			-- Wishbone Visible
	Tune.SusRadius		= .2			-- Suspension Coil Radius
	Tune.SusThickness	= .1			-- Suspension Coil Thickness
	Tune.SusColor		= "Bright red"	-- Suspension Color [BrickColor]
	Tune.SusCoilCount	= 6				-- Suspension Coil Count
	Tune.WsColor		= "Black"		-- Wishbone Color [BrickColor]
	Tune.WsThickness	= .1			-- Wishbone Rod Thickness
--Values--
local Drain = script.Parent.Values.Drain

stat = Player:WaitForChild("Data")

RS.Heartbeat:Connect(function(Time)
	if State:GetState() == "boost" then
		ElapsedTime = ElapsedTime + Time
		if math.clamp(ElapsedTime, 0.3, 0.8) > 0.3 then
			ElapsedTime = 0
			stat.BoostGauge.Value = stat.BoostGauge.Value - Drain.Value
		end
	else
		ElapsedTime = 0
	end
end)
-- GLOBALS

export type Map<K, V> = {[K]: V}

export type Array<V> = {V}
--set suitcase name to the player's name
handle.BottomGui.OwnerName.Text = player.Name
handle.TopGui.OwnerName.Text = player.Name
script.Parent.PlayerName.Value = player.Name
-- Important parts --
local faucet = p.Faucet
local steam = p:WaitForChild("Steam")
-- Libraries
local Libraries = Tool:WaitForChild 'Libraries'
local Signal = require(Libraries:WaitForChild 'Signal')
local Make = require(Libraries:WaitForChild 'Make')
local ListenForManualWindowTrigger = require(Tool.Core:WaitForChild('ListenForManualWindowTrigger'))
--//Toggle//--
Button.MouseButton1Click:Connect(function()
	if EmotesMenu.Visible == false then
		EmotesMenu.Visible = true
		
	else
		EmotesMenu.Visible = false
	end
end)
-- Decompiled with the Synapse X Luau decompiler.

local l__LocalPlayer__1 = game.Players.LocalPlayer;
local u1 = require(game:GetService("ReplicatedStorage"):WaitForChild("Achievements"));
local u2 = script:FindFirstAncestor("MainUI");
local l__TweenService__3 = game:GetService("TweenService");
return function(p1, p2)
	local v2 = u1[p2];
	if v2 then
		local v3 = u2.AchievementsHolder.Achievement:Clone();
		v3.Size = UDim2.new(0, 0, 0, 0);
		v3.Frame.Position = UDim2.new(1.1, 0, 0, 0);
		v3.Name = "LiveAchievement";
		v3.Visible = true;
		for v4, v5 in pairs(v2) do
			local v6 = v3.Frame.Details:FindFirstChild(v4);
			if v6 then
				v6.Text = v5;
			end;
		end;
		if v2.Image then
			v3.Frame.ImageLabel.Image = v2.Image;
		elseif v2.BadgeId then
			v3.Frame.ImageLabel.Image = "rbxassetid://" .. game.BadgeService:GetBadgeInfoAsync(v2.BadgeId).IconImageId;
		end;
		v3.Parent = u2.AchievementsHolder;
		v3.Sound:Play();
		v3:TweenSize(UDim2.new(1, 0, 0.2, 0), "In", "Quad", 0.8, true);
		wait(0.8);
		v3.Frame:TweenPosition(UDim2.new(0, 0, 0, 0), "Out", "Quad", 0.5, true);
		l__TweenService__3:Create(v3.Frame.Glow, TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {
			ImageTransparency = 1
		}):Play();
		wait(8);
		v3.Frame:TweenPosition(UDim2.new(1.1, 0, 0, 0), "In", "Quad", 0.5, true);
		wait(0.5);
		v3:TweenSize(UDim2.new(1, 0, -0.1, 0), "InOut", "Quad", 0.5, true);
		wait(0.5);
		v3:Destroy();
	end;
end;
---[[ Fade Out and In Settings ]]
module.ChatWindowBackgroundFadeOutTime = 3.5 --Chat background will fade out after this many seconds.
module.ChatWindowTextFadeOutTime = 1 --Chat text will fade out after this many seconds.
module.ChatDefaultFadeDuration = 0.8
module.ChatShouldFadeInFromNewInformation = false
module.ChatAnimationFPS = 20.0
--		print(animName .. " " .. idx .. " [" .. origRoll .. "]")
		local anim = animTable[animName][idx].anim

		-- load it to the humanoid; get AnimationTrack
		currentAnimTrack = humanoid:LoadAnimation(anim)
		 
		-- play the animation
		currentAnimTrack:Play(transitionTime)
		currentAnim = animName

		-- set up keyframe name triggers
		if (currentAnimKeyframeHandler ~= nil) then
			currentAnimKeyframeHandler:disconnect()
		end
		currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
	end
end
-------------------------
 
mouse.KeyDown:connect(function (key)
    key = string.lower(key)
        if key == "a" then
            	a = true
        elseif key == "d" then
                d = true
        elseif key == "w" then
                w = true
                rwd.Throttle = 1
				rwd.Torque = tq
				lwd.Throttle = 1
				lwd.Torque = ftq
				rrwd.Throttle = 1
				rrwd.Torque = ftq
				rwd.MaxSpeed = 185
				lwd.MaxSpeed = 185
				rrwd.MaxSpeed = 185
                carSeat.Throttle = 1
                carSeat.Torque = 0
                elseif key == "s" then
                s = true    
                carSeat.Throttle = 0
                carSeat.Torque = 0
				rwd.Throttle = -1
				rwd.Torque = brk
				lwd.Throttle = -1
				lwd.Torque = brk
				rrwd.Throttle = -1
				rrwd.Torque = brk
				rwd.MaxSpeed = 25
				lwd.MaxSpeed = 25
				rrwd.MaxSpeed = 25
                end
end)
 
mouse.KeyUp:connect(function (key)
    key = string.lower(key)
        if key == "a" then
                print("a up")
                if d == false then
                m.DesiredAngle = 0
                        n.DesiredAngle = m.DesiredAngle
                end
        elseif key == "d" then
                print("d up")
                if a == false then
                m.DesiredAngle = 0
                        n.DesiredAngle = m.DesiredAngle
end
        end
        a = false
        d = false
end)
 
mouse.KeyUp:connect(function (key)
    key = string.lower(key)
if key == "w" or key == "s" then
        rwd.Throttle = 0
        rwd.Torque = 0
	    lwd.Throttle = 0
		lwd.Torque = 0
		rrwd.Throttle = 0
		rrwd.Torque = 0

       carSeat.Throttle = 0
carSeat.Torque = cst
        end
end)   
               
 
 
limitButton.MouseButton1Click:connect(function()
--You dont need to delete this text.
--PUT INSIDE a BUTTON in StarterGui
--Make sure to make a frame for the menu to pop up then go to properties > Visible [Off]
script.Parent.MouseButton1Click:Connect (function()
	script.Parent.Parent.Visible = false
end)
--------------------
--| Script Logic |--
--------------------

BaseShot = Instance.new('Part')
BaseShot.Name = 'Effect'
BaseShot.FormFactor = Enum.FormFactor.Custom
BaseShot.Size = Vector3.new(0.2, 0.2, 3)
BaseShot.CanCollide = false
BaseShot.BrickColor = BrickColor.new('Toothpaste')
SelectionBoxify(BaseShot)
Light(BaseShot)
HitFadeSound:Clone().Parent = BaseShot

Tool.Equipped:connect(OnEquipped)
Tool.Unequipped:connect(OnUnequipped)
Tool.Click.OnServerEvent:connect(function(client, hit)
	if client.Character == Tool.Parent then
		OnActivated(hit)
	end
end)
--Rescripted by Luckymaxer

Tool = script.Parent
Handle = Tool:WaitForChild("Handle")

Players = game:GetService("Players")

Animations = {}

ServerControl = Tool:WaitForChild("ServerControl")
ClientControl = Tool:WaitForChild("ClientControl")

Rate = (1 / 60)

ToolEquipped = false

function CheckIfAlive()
	return (((Character and Character.Parent and Humanoid and Humanoid.Parent and Humanoid.Health > 0 and Player and Player.Parent) and true) or false)
end

function Equipped(Mouse)
	Character = Tool.Parent
	Player = Players:GetPlayerFromCharacter(Character)
	Humanoid = Character:FindFirstChild("Humanoid")
	ToolEquipped = true
	if not CheckIfAlive() then
		return
	end
	Spawn(function()
		PlayerMouse = Mouse
		Mouse.Button1Down:connect(function()
			InvokeServer("Button1Click", {Down = true})
		end)
		Mouse.Button1Up:connect(function()
			InvokeServer("Button1Click", {Down = false})
		end)
	end)
end

function Unequipped()
	for i, v in pairs(Animations) do
		if v and v.AnimationTrack then
			v.AnimationTrack:Stop()
		end
	end
	Animations = {}
	ToolEquipped = false
end

function InvokeServer(mode, value)
	local ServerReturn = nil
	pcall(function()
		ServerReturn = ServerControl:InvokeServer(mode, value)
	end)
	return ServerReturn
end

function OnClientInvoke(mode, value)
	if mode == "PlaySound" and value then
		value:Play()
	elseif mode == "StopSound" and value then
		value:Stop()
	elseif mode == "MousePosition" then
		return ((PlayerMouse and {Position = PlayerMouse.Hit.p, Target = PlayerMouse.Target}) or nil)
	end
end

ClientControl.OnClientInvoke = OnClientInvoke

Tool.Equipped:connect(Equipped)
Tool.Unequipped:connect(Unequipped)
--DO NOT CHANGE ANYTHING INSIDE OF THIS SCRIPT BESIDES WHAT YOU ARE TOLD TO UNLESS YOU KNOW WHAT YOU'RE DOING OR THE SCRIPT WILL NOT WORK!!
local hitPart = script.Parent
local debounce = true
local tool = game.ServerStorage.DeliciousCake -- Change "Sword" to the name of your tool, make sure your tool is in ServerStorage

hitPart.Touched:Connect(function(hit)
	if debounce == true then
		if hit.Parent:FindFirstChild("Humanoid") then
			local plr = game.Players:FindFirstChild(hit.Parent.Name)
			if plr then
				debounce = false
				hitPart.BrickColor = BrickColor.new("Bright red")
				tool:Clone().Parent = plr.Backpack
				wait(3) -- Change "3" to however long you want the player to have to wait before they can get the tool again
				debounce = true
				hitPart.BrickColor = BrickColor.new("Bright green")
			end
		end
	end
end)
--[[

A function which gets the character given one part in that character.

--]]

return function(p)
	while p and not p:FindFirstChild("Humanoid") do
		p = p.Parent;
	end
	return p;
end
--[[Engine]]
	--Torque Curve
	Tune.Horsepower		= 479		--	[TORQUE CURVE VISUAL]
	Tune.IdleRPM		= 700		--		https://www.desmos.com/calculator/2uo3hqwdhf
	Tune.PeakRPM		= 6000		--		Use sliders to manipulate values
	Tune.Redline		= 6700		--		Copy and paste slider values into the respective tune values
	Tune.EqPoint		= 5500
	Tune.PeakSharpness	= 7.5
	Tune.CurveMult		= 0.16
	
	--Incline Compensation
	Tune.InclineComp	= 4.7			-- Torque compensation multiplier for inclines (applies gradient from 0-90 degrees)
	
	--Misc
	Tune.RevAccel		= 150		-- RPM acceleration when clutch is off
	Tune.RevDecay		= 75		-- RPM decay when clutch is off
	Tune.RevBounce		= 500		-- RPM kickback from redline
	Tune.IdleThrottle	= 3			-- Percent throttle at idle
	Tune.ClutchTol		= 500		-- Clutch engagement threshold (higher = faster response)
-- Placeholder texture can be any roblox asset link
local initialTexture = ""

local RowCount = 3 -- rows in one sprite
local ColCount = 4 -- columns in one sprite
local perImageSpriteCount = RowCount * ColCount
local width = 229 -- image rect size
local height = 341

local framesInTotal = 12
assert(numImages * RowCount * ColCount >= framesInTotal)

local animPeriod = 1 -- period for the whole animation, in seconds
assert(animPeriod > 0)

local curImageIdx = 0
local curSpriteIdx = 0

local fps = framesInTotal / animPeriod
local accumulatedTime = 0

local function AnimateImageSpriteSheet(dt)
	accumulatedTime = math.fmod(accumulatedTime + dt, animPeriod)
	curSpriteIdx = math.floor(accumulatedTime * fps)

	local prevImageIndex = curImageIdx
	curImageIdx = math.floor(curSpriteIdx / perImageSpriteCount)
	if prevImageIndex ~= curImageIdx then
		imageInstance.Image = imageAssetIDs[curImageIdx + 1]
	end

	local localSpriteIndex = curSpriteIdx - curImageIdx * perImageSpriteCount
	local row = math.floor(localSpriteIndex / ColCount)
	local col = localSpriteIndex - row * ColCount
	imageInstance.ImageRectOffset = Vector2.new(col * width, row * height)
end

Animator.Connection = nil

Animator.Init = function()
	Animator.Connection = game:GetService("RunService").RenderStepped:Connect(AnimateImageSpriteSheet)
end

Animator.Stop = function()
	if Animator.Connection then
		imageInstance.Image = initialTexture
		Animator.Connection:Disconnect()
	end
end


return Animator
-- Given a label, return a function which given a string,
-- right-aligns it preceding the colon in the label.
function getRightAlignedPrinter(label: string): PrintLabel
	-- Assume that the label contains a colon.
	local index = label:find(":")
	local suffix = label:sub(index)

	return function(string_: string, isExpectedCall: boolean)
		local retval
		if isExpectedCall then
			retval = "->" .. string.rep(" ", math.max(0, index - 3 - #string_))
		else
			retval = string.rep(" ", math.max(0, index - 1 - #string_))
		end

		return retval .. string_ .. suffix
	end
end
--[[Drivetrain]]	
	Tune.Config			= "RWD"		--"FWD" , "RWD" , "AWD"
	
	--Differential Settings	
	Tune.FDiffSlipThres	= 50		-- 1 - 100%				(Max threshold of applying full lock determined by deviation from avg speed)
	Tune.FDiffLockThres	= 50		-- 0 - 100%				(0 - Bias toward slower wheel, 100 - Bias toward faster wheel)
	Tune.RDiffSlipThres	= 15		-- 1 - 100%
	Tune.RDiffLockThres	= 50		-- 0 - 100%
	Tune.CDiffSlipThres	= 50		-- 1 - 100%				[AWD Only]
	Tune.CDiffLockThres	= 50		-- 0 - 100%				[AWD Only]
	
	--Traction Control Settings
	Tune.TCSEnabled		= true		-- Implements TCS
	Tune.TCSThreshold	= 20		-- Slip speed allowed before TCS starts working (in SPS)
	Tune.TCSGradient	= 20		-- Slip speed gradient between 0 to max reduction (in SPS)
	Tune.TCSLimit		= 10		-- Minimum amount of torque at max reduction (in percent)
--                                                     in the mainUI
infoButton.MouseButton1Down:Connect(function()
	topbar_infoButton_p:Play()
	darkenScreen()
	showAboutWindow()
	aboutWindow.Visible = true
end)

infoButton.MouseButton1Up:Connect(function()
	topbar_infoButton_f:Cancel()
	topbar_infobutton_r:Play()
	topbar_infobutton_r.Completed:Wait()
	topbar_infoButton_nf:Play()
end)

local aboutCloseButton = aboutWindow.Close
------------------------------------------------------------------------
-- parse a function name specification
-- * used in funcstat()
------------------------------------------------------------------------
function luaY:funcname(ls, v)
  -- funcname -> NAME {field} [':' NAME]
  local needself = false
  self:singlevar(ls, v)
  while ls.t.token == "." do
    self:field(ls, v)
  end
  if ls.t.token == ":" then
    needself = true
    self:field(ls, v)
  end
  return needself
end