Pinkstack/roblox-luau-corpus-text huggingface dataset:
--[[Transmission]]


	Tune.TransModes		= {"Auto", "Semi", "Manual"}								--[[
	[Modes]
		"Auto"		: Automatic shifting
		"Semi"		: Clutchless manual shifting, dual clutch transmission
		"Manual"	: Manual shifting with clutch
		
		>Include within brackets
			eg: {"Semi"} or {"Auto", "Manual"}								
		>First mode is default mode													]]
	
	--Automatic Settings
	Tune.AutoShiftMode	= "Speed"												--[[
	[Modes]
		"Speed"		: Shifts based on wheel speed
		"RPM"		: Shifts based on RPM											]]	
	Tune.AutoUpThresh	= -200		--Automatic upshift point 	(relative to peak RPM, positive = Over-rev)
	Tune.AutoDownThresh = 1400		--Automatic downshift point (relative to peak RPM, positive = Under-rev)
	
	--Gear Ratios
	Tune.FinalDrive		= 3.30			-- Gearing determines top speed and wheel torque
	Tune.Ratios			= {				-- Higher ratio = more torque, Lower ratio = higher top speed
		--[[Reverse]]	3.30		,	-- Copy and paste a ratio to add a gear
		--[[Neutral]]	0			,	-- Ratios can also be deleted
		--[[ 1 ]]		2.89		,	-- Reverse, Neutral, and 1st gear are required
		--[[ 2 ]]		1.99		,
		--[[ 3 ]]		1.51		,
		--[[ 4 ]]		1.20		,
		--[[ 5 ]]		1.00		,
		--[[ 6 ]]		0.85		,
	}
	Tune.FDMult			= 1.5			-- Ratio multiplier (Change this value instead of FinalDrive if car is struggling with torque ; Default = 1)
--Engine Curve



local HP=_Tune.Horsepower/100
local HP_T=((_Tune.Horsepower*((_TPsi)*(_Tune.T_Efficiency/10))/7.5)/2)/100
local HP_S=((_Tune.Horsepower*((_SPsi)*(_Tune.S_Efficiency/10))/7.5)/2)/100

local Peak=_Tune.PeakRPM/1000
local Sharpness=_Tune.PeakSharpness
local CurveMult=_Tune.CurveMult
local EQ=_Tune.EqPoint/1000

function CurveN(RPM)
	RPM=RPM/1000
	return ((-(RPM-Peak)^2)*math.min(HP/(Peak^2),CurveMult^(Peak/HP))+HP)*(RPM-((RPM^Sharpness)/(Sharpness*Peak^(Sharpness-1))))
end
local PeakCurveN = CurveN(_Tune.PeakRPM)

function CurveT(RPM)
	RPM=RPM/1000
	return ((-(RPM-Peak)^2)*math.min(HP_T/(Peak^2),CurveMult^(Peak/HP_T))+HP_T)*(RPM-((RPM^Sharpness)/(Sharpness*Peak^(Sharpness-1))))
end
local PeakCurveT = CurveT(_Tune.PeakRPM)

function CurveS(RPM)
	RPM=RPM/1000
	return ((-(RPM-Peak)^2)*math.min(HP_S/(Peak^2),CurveMult^(Peak/HP_S))+HP_S)*(RPM-((RPM^Sharpness)/(Sharpness*Peak^(Sharpness-1))))
end
local PeakCurveS = CurveS(_Tune.PeakRPM)
-- These controllers handle only walk/run movement, jumping is handled by the
-- TouchJump controller if any of these are active


local ClickToMove = require(script:WaitForChild("ClickToMoveController"))
local TouchThumbstick = require(script:WaitForChild("TouchThumbstick"))
local TouchThumbpad = require(script:WaitForChild("TouchThumbpad"))
local TouchJump = require(script:WaitForChild("TouchJump"))

local VehicleController = require(script:WaitForChild("VehicleController"))

local CONTROL_ACTION_PRIORITY = Enum.ContextActionPriority.Default.Value
-- return to idle if finishing an emote


if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
oldAnim = "idle"
end

currentAnim = ""
currentAnimInstance = nil
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end

if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop()
currentAnimTrack:Destroy()
currentAnimTrack = nil
end
return oldAnim
end

function setAnimationSpeed(speed)
if speed ~= currentAnimSpeed then
currentAnimSpeed = speed
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
end
end

function keyFrameReachedFunc(frameName)
if (frameName == "End") then

local repeatAnim = currentAnim
-- Preload animations


function playAnimation(animName, transitionTime, humanoid) 
		
	local roll = math.random(1, animTable[animName].totalWeight) 
	local origRoll = roll
	local idx = 1
	while (roll > animTable[animName][idx].weight) do
		roll = roll - animTable[animName][idx].weight
		idx = idx + 1
	end
--Still Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill
--Still Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill
--Still Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill--Still Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill till Chill
--



local characterClone = require(game.ReplicatedStorage.CharacterClone)
local clones = {}

local function onCharacter(character)
	if (character) then
		character.Archivable = true
		character:WaitForChild("Humanoid") -- weird bug
		
		local cloneA = characterClone.new(character)
		local cloneB = characterClone.new(character)
		dualWorld.PortalA:AddToWorld(cloneA.Clone)
		dualWorld.PortalB:AddToWorld(cloneB.Clone)
		table.insert(clones, cloneA)
		table.insert(clones, cloneB)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(onCharacter)
end)

wait(1)

for _, player in next, game.Players:GetPlayers() do
	onCharacter(player.Character)
	player.CharacterAdded:Connect(onCharacter)
end

game:GetService("RunService").RenderStepped:Connect(function(dt)
	for i = 1, #clones do
		clones[i]:Update()
	end
end)
--


local u_categories = options.unicodeData and require(script:WaitForChild("_unicodechar_category"));
local chr_scripts = options.unicodeData and require(script:WaitForChild("_scripts"));
local xuc_chr = options.unicodeData and require(script:WaitForChild("_xuc"));
local proxy = setmetatable({ }, { __mode = 'k' });
local re, re_m, match_m = { }, { }, { };
local lockmsg;
-- slash1


Attack(target,fleshDamage)
else
Move(target.Character.PrimaryPart.Position)
end
else
target,targetType = nil,nil
end
wait(.3)
end

elseif targetType == "Model" then
while target and target.PrimaryPart and target:IsDescendantOf(workspace) and lastLock == sessionLock do
Move(target.PrimaryPart.Position)
local dist = (root.Position-target.PrimaryPart.Position).magnitude
if dist < 15 then
-- Remove the default loading screen


ReplicatedFirst:RemoveDefaultLoadingScreen()

local tweenInfo = TweenInfo.new(4, Enum.EasingStyle.Linear, Enum.EasingDirection.In, -1)
local tween = TweenService:Create(loadingRing, tweenInfo, {Rotation = 360})
tween:Play()

wait(12)  -- Force screen to appear for a minimum number of seconds
if not game:IsLoaded() then
	game.Loaded:Wait()
end
screenGui:Destroy()
----------------------------------------------------------------------------------------------------
--------------------=[ CFRAME ]=--------------------------------------------------------------------
----------------------------------------------------------------------------------------------------


	,EnableHolster = false
	,HolsterTo = 'Torso'				 -- Put the name of the body part you wanna holster to
	,HolsterPos = CFrame.new(0,0,0) * CFrame.Angles(math.rad(0),math.rad(0),math.rad(0))
	
	,RightArmPos = CFrame.new(-0.85, -0.2, -1.2) * CFrame.Angles(math.rad(-90), math.rad(0), math.rad(0))	--Server
	,LeftArmPos = CFrame.new(1.05,0.9,-1.4) * CFrame.Angles(math.rad(-100),math.rad(25),math.rad(-20))	--server
	
	,ServerGunPos = CFrame.new(-.3, -1, -0.4) * CFrame.Angles(math.rad(-90), math.rad(0), math.rad(0))
	,GunPos = CFrame.new(0.15, -0.15, 1) * CFrame.Angles(math.rad(90), math.rad(0), math.rad(0))

	,RightPos = CFrame.new(-.65, -0.2, -1) * CFrame.Angles(math.rad(-90), math.rad(0), math.rad(0))	--Client
	,LeftPos = CFrame.new(1.2,0.1,-1.6) * CFrame.Angles(math.rad(-120),math.rad(35),math.rad(-20))	--Client
}

return Config
----------------------------------------------------------------------------------------------------
-----------------=[ RECOIL & PRECISAO ]=------------------------------------------------------------
----------------------------------------------------------------------------------------------------


	,VRecoil = {20,25}				--- Vertical Recoil
	,HRecoil = {10,15}				--- Horizontal Recoil
	,AimRecover = 1					---- Between 0 & 1
	
	,RecoilPunch = 1.25
	,VPunchBase = 15				--- Vertical Punch
	,HPunchBase = 7					--- Horizontal Punch
	,DPunchBase = 1 				--- Tilt Punch | useless
	
	,AimRecoilReduction = 1 		--- Recoil Reduction Factor While Aiming (Do not set to 0)
	,PunchRecover = 0.1
	,MinRecoilPower = 1
	,MaxRecoilPower = 3
	,RecoilPowerStepAmount = 1
	
	,MinSpread = 0					--- Min bullet spread value | Studs
	,MaxSpread = 75					--- Max bullet spread value | Studs
	,AimInaccuracyStepAmount = 5
	,WalkMultiplier = 0				--- Bullet spread based on player speed

	,SwayBase = 0.25				--- Weapon Base Sway | Studs
	,MaxSway =	1					--- Max sway value based on player stamina | Studs
--------------------[ MATH FUNCTIONS ]------------------------------------------------



function Map(Val, fromLow, fromHigh, toLow, toHigh)
	return (Val - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow
end

function numLerp(A, B, Alpha)
	return A + (B - A) * Alpha
end

function RAND(Min, Max, Accuracy)
	return numLerp(Min, Max, math.random())
	--[[local Inverse = 1 / (Accuracy or 1)
	return (math.random(Min * Inverse, Max * Inverse) / Inverse)]]
end

function Round(Num, toNearest)
	return math.floor(Num / toNearest + 0.5) * toNearest
end

function getNearestPoint(A, B, Origin)
	local A2 = (A - Origin).magnitude
	local B2 = (B - Origin).magnitude
	return (math.min(A2, B2) == A2 and A or B)
end
--//Setup//--


local WindLines = require(script.WindLines)
local WindShake = require(script.WindShake)

local WindSpeed = 20
local WindDirection = Vector3.new(1, 0, -0.15)

local WindShakeSettings = {
	WindPower = 3,
	WindSpeed = WindSpeed,
	WindDirection = WindDirection
}

local WindLinesSettings = {
	WindDirection = WindDirection,
	WindSpeed = WindSpeed,
	LifeTime = 9,
	SpawnRate = 15
}

local ShakableObjects = {
	"Leaf",
	"Leaves",
	"Bush", 
	"FLower"
}
--!strict
--[=[
  @function removeValue
  @within Dictionary

  @param dictionary {[K]: V} -- The dictionary to remove the value from.
  @param value V -- The value to remove.
  @return {[K]: V} -- The dictionary without the given value.

  Removes the given value from the given dictionary.

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

  local withoutHello = RemoveValue(dictionary, "roblox") -- { goodbye = "world" }
  local withoutGoodbye = RemoveValue(dictionary, "world") -- { hello = "roblox" }
  ```
]=]


local function removeValue<K, V>(dictionary: { [K]: V }, value: V): { [K]: V }
	local result = {}

	for key, v in pairs(dictionary) do
		if v ~= value then
			result[key] = v
		end
	end

	return result
end

return removeValue
-- RANK, RANK NAMES & SPECIFIC USERS


Ranks = {
	{5,	"Owner",		};
	{4,	"HeadAdmin",	{"",0},	};
	{3,	"Admin",		{"",0},	};
	{2,	"Mod",			{"",0},	};
	{1,	"VIP",			{"",0},	};
	{0,	"NonAdmin",		};
};
--------RIGHT DOOR --------



game.Workspace.doorright.l12.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l21.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l33.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l42.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l51.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l63.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
game.Workspace.doorright.l72.BrickColor = BrickColor.new(game.Workspace.Lighting.cyan.Value)
--TheNexusAvenger
--Runs the server-side rocket launcher.



local Tool = script.Parent
local Handle = Tool:WaitForChild("Handle")
local EquipSound = Handle:WaitForChild("EquipSound")
local ReloadSound = Handle:WaitForChild("ReloadSound")

local Resources = require(script.Parent:WaitForChild("Resources"))
local RocketCreator = require(Resources:GetResource("RocketCreator"))
local BufferCreator = require(Resources:GetResource("BufferCreator"))
local RemoteEventCreator = require(Resources:GetResource("RemoteEventCreator"))
local Configuration = require(Resources:GetResource("Configuration"))

local ROCKET_RELOAD_TIME = Configuration.ROCKET_RELOAD_TIME

local RocketBuffer = BufferCreator:CreateServerBuffer("RocketBuffer")
local FireRocketEvent = RemoteEventCreator:CreateRemoteEvent("FireRocket")

local CurrentPlayer,CurrentCharacter
local CurrentHandRocket,CurrentRocket
local Equipped = false
local ToolEnabled = true
-- rbxthumb://type=Asset&id=00000000&w=420&h=420 -- use 150x150 for less memory


local function makeButton(v)
	local button; button = Button.new({
		Name = v.Name,
		Icon = "rbxthumb://type=Asset&id=" .. v.Id .. "&w=150&h=150",
		AssetId = v.Id,
		ActivatedCallback = function(inputObject)
			remoteEvent:FireServer("wear", v.Id)
		end,
		DetailsCallback = function(inputObject)
			purchasePrompt:Prompt(v.Id)
		end,
	})
	button:SetSelected(isWearing(v.Id))
	button:Parent(scrollingFrame)
	return button
end
--[[Brakes]]


	Tune.ABSEnabled		= true		-- Implements ABS
	Tune.ABSThreshold	= 20		-- Slip speed allowed before ABS starts working (in SPS) 

	Tune.FBrakeForce	= 2500		-- Front brake force
	Tune.RBrakeForce	= 1500		-- Rear brake force
	Tune.PBrakeForce	= 5000		-- Handbrake force
	
	Tune.FLgcyBForce	= 15000		-- Front brake force [PGS OFF]
	Tune.RLgcyBForce	= 10000		-- Rear brake force [PGS OFF]
	Tune.LgcyPBForce	= 25000		-- Handbrake force [PGS OFF]
--[[Driver Handling]]



	--Driver Sit	
	car.DriveSeat.ChildAdded:connect(function(child)
		if child.Name=="SeatWeld" and child:IsA("Weld") and game.Players:GetPlayerFromCharacter(child.Part1.Parent)~=nil then
			--Distribute Client Interface
			local p=game.Players:GetPlayerFromCharacter(child.Part1.Parent)
			car.DriveSeat:SetNetworkOwner(p)
			local g=script.Parent["A-Chassis Interface"]:Clone()
			g.Parent=p.PlayerGui
		end
	end)
	
	--Driver Leave
	car.DriveSeat.ChildRemoved:connect(function(child)
		if child.Name=="SeatWeld" and child:IsA("Weld") then
			--Remove Flip Force
			if car.DriveSeat:FindFirstChild("Flip")~=nil then
				car.DriveSeat.Flip.MaxTorque = Vector3.new()
			end
			
			--Remove Wheel Force
			for i,v in pairs(car.Wheels:GetChildren()) do
				if v:FindFirstChild("#AV")~=nil then
					if v["#AV"]:IsA("BodyAngularVelocity") then
						if v["#AV"].AngularVelocity.Magnitude>0 then
							v["#AV"].AngularVelocity = Vector3.new()
							v["#AV"].MaxTorque = Vector3.new()
						end
					else
						if v["#AV"].AngularVelocity>0 then
							v["#AV"].AngularVelocity = 0
							v["#AV"].MotorMaxTorque = 0
						end
					end
				end
			end
		end
	end)
-----------------------


if f2==1 then f2=0
	local b=script.b:Clone()
	b.Parent=script.Parent.PS.bu
	b.Position=UDim2.new(0,po2.X,0,po2.Y+6)
	b.BackgroundColor3=p2.BackgroundColor3
	b.inf.Value=Vector3.new(-1,y2)
end
if z2==0 and s2==0 then
po2=po2+Vector3.new(x2,y2)/3 end
po2=po2.X<44 and Vector3.new(44,po2.Y)or po2
po2=po2.X>68 and Vector3.new(68,po2.Y)or po2
po2=po2.Y<0 and Vector3.new(po2.X,0)or po2
po2=po2.Y>25 and Vector3.new(po2.X,25)or po2
p2.Position=UDim2.new(0,po2.X,0,po2.Y)
local fr1,fr2='b'
if s2==1 then fr1='k'fr2='k'
elseif z2==1 then
fr1='b2'
fr2=y2==0 and's1'or y2==1 and's3'or's2'
elseif math.abs(x2)+math.abs(y2)>0 then
fr1='b'
fr2=math.sin(tick()*8)>0 and'l1'or'l2'
else
fr1='b'
fr2='l2'
end
for _,v in pairs(p2:GetChildren())do
if v.Name==fr1 or v.Name==fr2 then
v.Visible=true else v.Visible=false
end end
--Make NPC jump


local function setJumpState(self)
	pcall(function()
		if self._humanoid:GetState() ~= Enum.HumanoidStateType.Jumping and self._humanoid:GetState() ~= Enum.HumanoidStateType.Freefall then
			self._humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		end
	end)
end
-- Captions


local captionContainer = Instance.new("Frame")
captionContainer.Name = "CaptionContainer"
captionContainer.BackgroundTransparency = 1
captionContainer.AnchorPoint = Vector2.new(0, 0)
captionContainer.ClipsDescendants = true
captionContainer.ZIndex = 30
captionContainer.Visible = true
captionContainer.Parent = iconContainer
captionContainer.Active = false

local captionFrame = Instance.new("Frame")
captionFrame.Name = "CaptionFrame"
captionFrame.BorderSizePixel = 0
captionFrame.AnchorPoint = Vector2.new(0.5,0.5)
captionFrame.Position = UDim2.new(0.5,0,0.5,0)
captionFrame.Size = UDim2.new(1,0,1,0)
captionFrame.ZIndex = 31
captionFrame.Parent = captionContainer
captionFrame.Active = false

local captionLabel = Instance.new("TextLabel")
captionLabel.Name = "CaptionLabel"
captionLabel.BackgroundTransparency = 1
captionLabel.AnchorPoint = Vector2.new(0.5,0.5)
captionLabel.Position = UDim2.new(0.5,0,0.56,0)
captionLabel.TextXAlignment = Enum.TextXAlignment.Center
captionLabel.RichText = true
captionLabel.ZIndex = 32
captionLabel.Parent = captionContainer
captionLabel.Active = false

local captionCorner = Instance.new("UICorner")
captionCorner.Name = "CaptionCorner"
captionCorner.Parent = captionFrame

local captionOverlineContainer = Instance.new("Frame")
captionOverlineContainer.Name = "CaptionOverlineContainer"
captionOverlineContainer.BackgroundTransparency = 1
captionOverlineContainer.AnchorPoint = Vector2.new(0.5,0.5)
captionOverlineContainer.Position = UDim2.new(0.5,0,-0.5,3)
captionOverlineContainer.Size = UDim2.new(1,0,1,0)
captionOverlineContainer.ZIndex = 33
captionOverlineContainer.ClipsDescendants = true
captionOverlineContainer.Parent = captionContainer
captionOverlineContainer.Active = false

local captionOverline = Instance.new("Frame")
captionOverline.Name = "CaptionOverline"
captionOverline.AnchorPoint = Vector2.new(0.5,0.5)
captionOverline.Position = UDim2.new(0.5,0,1.5,-3)
captionOverline.Size = UDim2.new(1,0,1,0)
captionOverline.ZIndex = 34
captionOverline.Parent = captionOverlineContainer
captionOverline.Active = false

local captionOverlineCorner = captionCorner:Clone()
captionOverlineCorner.Name = "CaptionOverlineCorner"
captionOverlineCorner.Parent = captionOverline

local captionVisibilityBlocker = captionFrame:Clone()
captionVisibilityBlocker.Name = "CaptionVisibilityBlocker"
captionVisibilityBlocker.BackgroundTransparency = 1
captionVisibilityBlocker.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
captionVisibilityBlocker.ZIndex -= 1
captionVisibilityBlocker.Parent = captionFrame
captionVisibilityBlocker.Active = false

local captionVisibilityCorner = captionVisibilityBlocker.CaptionCorner
captionVisibilityCorner.Name = "CaptionVisibilityCorner"
--------------------------------------------------------------------


if brakewhistle == true then
	mouse.KeyDown:connect(function(key)
		if key == camkey and enabled == false then

			local seat = car.DriveSeat
			local effect = script.soundeffect:Clone()
			effect.Name = "soundeffectCop"
			effect.Parent = seat.Brakes

		elseif key == camkey and enabled == true then

			local seat = car.DriveSeat
			seat.Brakes.soundeffectCop:Destroy()

		end
		car.DriveSeat.ChildRemoved:Connect(function(child)

			if child.Name == "SeatWeld" then
				local seat = car.DriveSeat
				seat.Brakes.soundeffectCop:Destroy()
			end
		end)
	end)
end
-- Core connections


Connections = {};

function ClearConnections()
	-- Clears and disconnects temporary connections
	for Index, Connection in pairs(Connections) do
		Connection:Disconnect();
		Connections[Index] = nil;
	end;
end;

function InitializeUI()
	-- Sets up the UI

	-- Ensure UI has not yet been initialized
	if UI then
		return;
	end;

	-- Create the root UI
	UI = Instance.new('ScreenGui')
	UI.Name = 'Building Tools by F3X (UI)'

	-- Create dock
	local ToolList = {}
	local DockComponent = require(Tool:WaitForChild('UI'):WaitForChild('Dock'))
	local DockElement = Roact.createElement(DockComponent, {
		Core = Core;
		Tools = ToolList;
	})
	local DockHandle = Roact.mount(DockElement, UI, 'Dock')

	-- Provide API for adding tool buttons to dock
	local function AddToolButton(IconAssetId, HotkeyLabel, Tool)
		table.insert(ToolList, {
			IconAssetId = IconAssetId;
			HotkeyLabel = HotkeyLabel;
			Tool = Tool;
		})

		-- Update dock
		Roact.update(DockHandle, Roact.createElement(DockComponent, {
			Core = Core;
			Tools = Cryo.List.join(ToolList);
		}))
	end
	Core.AddToolButton = AddToolButton

	-- Clean up UI on tool teardown
	UIMaid = Maid.new()
	Tool.AncestryChanged:Connect(function (Item, Parent)
		if Parent == nil then
			UIMaid:Destroy()
		end
	end)
end

local UIElements = Tool:WaitForChild 'UI'
local ExplorerTemplate = require(UIElements:WaitForChild 'Explorer')
Core.ExplorerVisibilityChanged = Signal.new()
Core.ExplorerVisible = false

function ToggleExplorer()
	if not Core.ExplorerVisible then
		OpenExplorer()
	else
		CloseExplorer()
	end
end

function OpenExplorer()

	-- Ensure explorer not already open
	if ExplorerHandle then
		return
	end

	-- Initialize explorer
	Explorer = Roact.createElement(ExplorerTemplate, {
		Core = getfenv(0),
		Close = CloseExplorer,
		Scope = Targeting.Scope
	})

	-- Mount explorer
	ExplorerHandle = Roact.mount(Explorer, UI, 'Explorer')
	Core.ExplorerVisible = true

	-- Unmount explorer on tool cleanup
	UIMaid.Explorer = Support.Call(Roact.unmount, ExplorerHandle)
	UIMaid.ExplorerScope = Targeting.ScopeChanged:Connect(function (Scope)
		local UpdatedProps = Support.Merge({}, Explorer.props, { Scope = Scope })
		local UpdatedExplorer = Roact.createElement(ExplorerTemplate, UpdatedProps)
		ExplorerHandle = Roact.update(ExplorerHandle, UpdatedExplorer)
	end)

	-- Fire signal
	Core.ExplorerVisibilityChanged:Fire()
end

function CloseExplorer()

	-- Clean up explorer
	UIMaid.Explorer = nil
	UIMaid.ExplorerScope = nil
	ExplorerHandle = nil
	Core.ExplorerVisible = false

	-- Fire signal
	Core.ExplorerVisibilityChanged:Fire()
end
--		print(animName .. " * " .. idx .. " [" .. origRoll .. "]")


		local anim = animTable[animName][idx].anim

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

		currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
	end
end

function stopToolAnimations()
	local oldAnim = toolAnimName

	if (currentToolAnimKeyframeHandler ~= nil) then
		currentToolAnimKeyframeHandler:disconnect()
	end

	toolAnimName = ""
	if (toolAnimTrack ~= nil) then
		toolAnimTrack:Stop()
		toolAnimTrack:Destroy()
		toolAnimTrack = nil
	end


	return oldAnim
end