Quick actions

cmd+k|ctrl+k

Navigation

Languages

moonhigh autofarm

Snippet info

Language

Lua

Visibility

public

Author

hmm1x

Created

2023-09-02T23:34:32.208624Z

Updated

2023-09-03T20:45:25.453272Z

--https://v3rmillion.net/showthread.php?tid=723696
getupvalues = getupvalues or debug.getupvalues
setupvalue = setupvalue or debug.setupvalue
if not (getrawmetatable and getupvalues and setupvalue and (getreg or debug.getregistry)) then
	local h = Instance.new("Hint",workspace)
	h.Text = "Incompatible exploit."
	wait(3)
	h:Destroy()
	return
end

local ClickToMoveDisplay = {}

local FAILURE_ANIMATION_ID = "rbxassetid://2874840706"

local TrailDotIcon = "rbxasset://textures/ui/traildot.png"
local EndWaypointIcon = "rbxasset://textures/ui/waypoint.png"

local WaypointsAlwaysOnTop = true

local WAYPOINT_INCLUDE_FACTOR = 2
local LAST_DOT_DISTANCE = 3

local WAYPOINT_BILLBOARD_SIZE = UDim2.new(0, 1.68 * 25, 0, 2 * 25)

local ENDWAYPOINT_SIZE_OFFSET_MIN = Vector2.new(0, 0.5)
local ENDWAYPOINT_SIZE_OFFSET_MAX = Vector2.new(0, 1)

local FAIL_WAYPOINT_SIZE_OFFSET_CENTER = Vector2.new(0, 0.5)
local FAIL_WAYPOINT_SIZE_OFFSET_LEFT = Vector2.new(0.1, 0.5)
local FAIL_WAYPOINT_SIZE_OFFSET_RIGHT = Vector2.new(-0.1, 0.5)

local FAILURE_TWEEN_LENGTH = 0.125
local FAILURE_TWEEN_COUNT = 4

local TWEEN_WAYPOINT_THRESHOLD = 5

local TRAIL_DOT_PARENT_NAME = "ClickToMoveDisplay"

local TrailDotSize = Vector2.new(1.5, 1.5)

local TRAIL_DOT_MIN_SCALE = 1
local TRAIL_DOT_MIN_DISTANCE = 10
local TRAIL_DOT_MAX_SCALE = 2.5
local TRAIL_DOT_MAX_DISTANCE = 100

local PlayersService = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")

local LocalPlayer = PlayersService.LocalPlayer

local function CreateWaypointTemplates()
	local TrailDotTemplate = Instance.new("Part")
	TrailDotTemplate.Size = Vector3.new(1, 1, 1)
	TrailDotTemplate.Anchored = true
	TrailDotTemplate.CanCollide = false
	TrailDotTemplate.Name = "TrailDot"
	TrailDotTemplate.Transparency = 1
	local TrailDotImage = Instance.new("ImageHandleAdornment")
	TrailDotImage.Name = "TrailDotImage"
	TrailDotImage.Size = TrailDotSize
	TrailDotImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
	TrailDotImage.AlwaysOnTop = WaypointsAlwaysOnTop
	TrailDotImage.Image = TrailDotIcon
	TrailDotImage.Adornee = TrailDotTemplate
	TrailDotImage.Parent = TrailDotTemplate

	local EndWaypointTemplate = Instance.new("Part")
	EndWaypointTemplate.Size = Vector3.new(2, 2, 2)
	EndWaypointTemplate.Anchored = true
	EndWaypointTemplate.CanCollide = false
	EndWaypointTemplate.Name = "EndWaypoint"
	EndWaypointTemplate.Transparency = 1
	local EndWaypointImage = Instance.new("ImageHandleAdornment")
	EndWaypointImage.Name = "TrailDotImage"
	EndWaypointImage.Size = TrailDotSize
	EndWaypointImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
	EndWaypointImage.AlwaysOnTop = WaypointsAlwaysOnTop
	EndWaypointImage.Image = TrailDotIcon
	EndWaypointImage.Adornee = EndWaypointTemplate
	EndWaypointImage.Parent = EndWaypointTemplate
	local EndWaypointBillboard = Instance.new("BillboardGui")
	EndWaypointBillboard.Name = "EndWaypointBillboard"
	EndWaypointBillboard.Size = WAYPOINT_BILLBOARD_SIZE
	EndWaypointBillboard.LightInfluence = 0
	EndWaypointBillboard.SizeOffset = ENDWAYPOINT_SIZE_OFFSET_MIN
	EndWaypointBillboard.AlwaysOnTop = true
	EndWaypointBillboard.Adornee = EndWaypointTemplate
	EndWaypointBillboard.Parent = EndWaypointTemplate
	local EndWaypointImageLabel = Instance.new("ImageLabel")
	EndWaypointImageLabel.Image = EndWaypointIcon
	EndWaypointImageLabel.BackgroundTransparency = 1
	EndWaypointImageLabel.Size = UDim2.new(1, 0, 1, 0)
	EndWaypointImageLabel.Parent = EndWaypointBillboard


	local FailureWaypointTemplate = Instance.new("Part")
	FailureWaypointTemplate.Size = Vector3.new(2, 2, 2)
	FailureWaypointTemplate.Anchored = true
	FailureWaypointTemplate.CanCollide = false
	FailureWaypointTemplate.Name = "FailureWaypoint"
	FailureWaypointTemplate.Transparency = 1
	local FailureWaypointImage = Instance.new("ImageHandleAdornment")
	FailureWaypointImage.Name = "TrailDotImage"
	FailureWaypointImage.Size = TrailDotSize
	FailureWaypointImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
	FailureWaypointImage.AlwaysOnTop = WaypointsAlwaysOnTop
	FailureWaypointImage.Image = TrailDotIcon
	FailureWaypointImage.Adornee = FailureWaypointTemplate
	FailureWaypointImage.Parent = FailureWaypointTemplate
	local FailureWaypointBillboard = Instance.new("BillboardGui")
	FailureWaypointBillboard.Name = "FailureWaypointBillboard"
	FailureWaypointBillboard.Size = WAYPOINT_BILLBOARD_SIZE
	FailureWaypointBillboard.LightInfluence = 0
	FailureWaypointBillboard.SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_CENTER
	FailureWaypointBillboard.AlwaysOnTop = true
	FailureWaypointBillboard.Adornee = FailureWaypointTemplate
	FailureWaypointBillboard.Parent = FailureWaypointTemplate
	local FailureWaypointFrame = Instance.new("Frame")
	FailureWaypointFrame.BackgroundTransparency = 1
	FailureWaypointFrame.Size = UDim2.new(0, 0, 0, 0)
	FailureWaypointFrame.Position = UDim2.new(0.5, 0, 1, 0)
	FailureWaypointFrame.Parent = FailureWaypointBillboard
	local FailureWaypointImageLabel = Instance.new("ImageLabel")
	FailureWaypointImageLabel.Image = EndWaypointIcon
	FailureWaypointImageLabel.BackgroundTransparency = 1
	FailureWaypointImageLabel.Position = UDim2.new(
		0, -WAYPOINT_BILLBOARD_SIZE.X.Offset/2, 0, -WAYPOINT_BILLBOARD_SIZE.Y.Offset
	)
	FailureWaypointImageLabel.Size = WAYPOINT_BILLBOARD_SIZE
	FailureWaypointImageLabel.Parent = FailureWaypointFrame

	return TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate
end

local TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()

local function getTrailDotParent()
	local camera = Workspace.CurrentCamera
	local trailParent = camera:FindFirstChild(TRAIL_DOT_PARENT_NAME)
	if not trailParent then
		trailParent = Instance.new("Model")
		trailParent.Name = TRAIL_DOT_PARENT_NAME
		trailParent.Parent = camera
	end
	return trailParent
end

local function placePathWaypoint(waypointModel, position: Vector3)
	local ray = Ray.new(position + Vector3.new(0, 2.5, 0), Vector3.new(0, -10, 0))
	local hitPart, hitPoint, hitNormal = Workspace:FindPartOnRayWithIgnoreList(
		ray,
		{ Workspace.CurrentCamera, LocalPlayer.Character }
	)
	if hitPart then
		waypointModel.CFrame = CFrame.new(hitPoint, hitPoint + hitNormal)
		waypointModel.Parent = getTrailDotParent()
	end
end

local TrailDot = {}
TrailDot.__index = TrailDot

function TrailDot:Destroy()
	self.DisplayModel:Destroy()
end

function TrailDot:NewDisplayModel(position)
	local newDisplayModel: Part = TrailDotTemplate:Clone()
	placePathWaypoint(newDisplayModel, position)
	newDisplayModel.Parent=workspace.CurrentCamera
	return newDisplayModel
end

function TrailDot.new(position, closestWaypoint)
	local self = setmetatable({}, TrailDot)

	self.DisplayModel = self:NewDisplayModel(position)
	self.ClosestWayPoint = closestWaypoint

	return self
end

local EndWaypoint = {}
EndWaypoint.__index = EndWaypoint

function EndWaypoint:Destroy()
	self.Destroyed = true
	self.Tween:Cancel()
	self.DisplayModel:Destroy()
end

function EndWaypoint:NewDisplayModel(position)
	local newDisplayModel: Part = EndWaypointTemplate:Clone()
	placePathWaypoint(newDisplayModel, position)
	return newDisplayModel
end

function EndWaypoint:CreateTween()
	local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, -1, true)
	local tween = TweenService:Create(
		self.DisplayModel.EndWaypointBillboard,
		tweenInfo,
		{ SizeOffset = ENDWAYPOINT_SIZE_OFFSET_MAX }
	)
	tween:Play()
	return tween
end

function EndWaypoint:TweenInFrom(originalPosition: Vector3)
	local currentPositon: Vector3 = self.DisplayModel.Position
	local studsOffset = originalPosition - currentPositon
	self.DisplayModel.EndWaypointBillboard.StudsOffset = Vector3.new(0, studsOffset.Y, 0)
	local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
	local tween = TweenService:Create(
		self.DisplayModel.EndWaypointBillboard,
		tweenInfo,
		{ StudsOffset = Vector3.new(0, 0, 0) }
	)
	tween:Play()
	return tween
end

function EndWaypoint.new(position: Vector3, closestWaypoint: number?, originalPosition: Vector3?)
	local self = setmetatable({}, EndWaypoint)

	self.DisplayModel = self:NewDisplayModel(position)
	self.Destroyed = false
	if originalPosition and (originalPosition - position).Magnitude > TWEEN_WAYPOINT_THRESHOLD then
		self.Tween = self:TweenInFrom(originalPosition)
		coroutine.wrap(function()
			self.Tween.Completed:Wait()
			if not self.Destroyed then
				self.Tween = self:CreateTween()
			end
		end)()
	else
		self.Tween = self:CreateTween()
	end
	self.ClosestWayPoint = closestWaypoint

	return self
end

local FailureWaypoint = {}
FailureWaypoint.__index = FailureWaypoint

function FailureWaypoint:Hide()
	self.DisplayModel.Parent = nil
end

function FailureWaypoint:Destroy()
	self.DisplayModel:Destroy()
end

function FailureWaypoint:NewDisplayModel(position)
	local newDisplayModel: Part = FailureWaypointTemplate:Clone()
	placePathWaypoint(newDisplayModel, position)
	local ray = Ray.new(position + Vector3.new(0, 2.5, 0), Vector3.new(0, -10, 0))
	local hitPart, hitPoint, hitNormal = Workspace:FindPartOnRayWithIgnoreList(
		ray, { Workspace.CurrentCamera, LocalPlayer.Character }
	)
	if hitPart then
		newDisplayModel.CFrame = CFrame.new(hitPoint, hitPoint + hitNormal)
		newDisplayModel.Parent = getTrailDotParent()
	end
	return newDisplayModel
end

function FailureWaypoint:RunFailureTween()
	wait(FAILURE_TWEEN_LENGTH) -- Delay one tween length betfore starting tweening
	-- Tween out from center
	local tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH/2, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
	local tweenLeft = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
		{ SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_LEFT })
	tweenLeft:Play()

	local tweenLeftRoation = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
		{ Rotation = 10 })
	tweenLeftRoation:Play()

	tweenLeft.Completed:wait()

	-- Tween back and forth
	tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH, Enum.EasingStyle.Sine, Enum.EasingDirection.Out,
		FAILURE_TWEEN_COUNT - 1, true)
	local tweenSideToSide = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
		{ SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_RIGHT})
	tweenSideToSide:Play()

	-- Tween flash dark and roate left and right
	tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH, Enum.EasingStyle.Sine, Enum.EasingDirection.Out,
		FAILURE_TWEEN_COUNT - 1, true)
	local tweenFlash = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame.ImageLabel, tweenInfo,
		{ ImageColor3 = Color3.new(0.75, 0.75, 0.75)})
	tweenFlash:Play()

	local tweenRotate = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
		{ Rotation = -10 })
	tweenRotate:Play()

	tweenSideToSide.Completed:wait()

	-- Tween back to center
	tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH/2, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
	local tweenCenter = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
		{ SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_CENTER })
	tweenCenter:Play()

	local tweenRoation = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
		{ Rotation = 0 })
	tweenRoation:Play()

	tweenCenter.Completed:wait()

	wait(FAILURE_TWEEN_LENGTH) -- Delay one tween length betfore removing
end

function FailureWaypoint.new(position)
	local self = setmetatable({}, FailureWaypoint)

	self.DisplayModel = self:NewDisplayModel(position)

	return self
end

local failureAnimation = Instance.new("Animation")
failureAnimation.AnimationId = FAILURE_ANIMATION_ID

local lastHumanoid = nil
local lastFailureAnimationTrack: AnimationTrack? = nil

local function getFailureAnimationTrack(myHumanoid)
	if myHumanoid == lastHumanoid then
		return lastFailureAnimationTrack
	end
	lastFailureAnimationTrack = myHumanoid:LoadAnimation(failureAnimation)
	assert(lastFailureAnimationTrack, "")
	lastFailureAnimationTrack.Priority = Enum.AnimationPriority.Action
	lastFailureAnimationTrack.Looped = false
	return lastFailureAnimationTrack
end

local function findPlayerHumanoid()
	local character = LocalPlayer.Character
	if character then
		return character:FindFirstChildOfClass("Humanoid")
	end
end

local function createTrailDots(wayPoints: {PathWaypoint}, originalEndWaypoint: Vector3)
	local newTrailDots = {}
	local count = 1
	for i = 1, #wayPoints - 1 do
		local closeToEnd = (wayPoints[i].Position - wayPoints[#wayPoints].Position).Magnitude < LAST_DOT_DISTANCE
		local includeWaypoint = i % WAYPOINT_INCLUDE_FACTOR == 0 and not closeToEnd
		if includeWaypoint then
			local trailDot = TrailDot.new(wayPoints[i].Position, i)
			newTrailDots[count] = trailDot
			count = count + 1
		end
	end

	local newEndWaypoint = EndWaypoint.new(wayPoints[#wayPoints].Position, #wayPoints, originalEndWaypoint)
	table.insert(newTrailDots, newEndWaypoint)

	local reversedTrailDots = {}
	count = 1
	for i = #newTrailDots, 1, -1 do
		reversedTrailDots[count] = newTrailDots[i]
		count = count + 1
	end
	return reversedTrailDots
end

local function getTrailDotScale(distanceToCamera: number, defaultSize: Vector2)
	local rangeLength = TRAIL_DOT_MAX_DISTANCE - TRAIL_DOT_MIN_DISTANCE
	local inRangePoint = math.clamp(distanceToCamera - TRAIL_DOT_MIN_DISTANCE, 0, rangeLength)/rangeLength
	local scale = TRAIL_DOT_MIN_SCALE + (TRAIL_DOT_MAX_SCALE - TRAIL_DOT_MIN_SCALE)*inRangePoint
	return defaultSize * scale
end

local createPathCount = 0
-- originalEndWaypoint is optional, causes the waypoint to tween from that position.
function ClickToMoveDisplay.CreatePathDisplay(wayPoints, originalEndWaypoint)
	createPathCount = createPathCount + 1
	local trailDots = createTrailDots(wayPoints, originalEndWaypoint)

	local function removePathBeforePoint(wayPointNumber)
		-- kill all trailDots before and at wayPointNumber
		for i = #trailDots, 1, -1 do
			local trailDot = trailDots[i]
			if trailDot.ClosestWayPoint <= wayPointNumber then
				trailDot:Destroy()
				trailDots[i] = nil
			else
				break
			end
		end
	end

	local reiszeTrailDotsUpdateName = "ClickToMoveResizeTrail" ..createPathCount
	local function resizeTrailDots()
		if #trailDots == 0 then
			RunService:UnbindFromRenderStep(reiszeTrailDotsUpdateName)
			return
		end
		local cameraPos = Workspace.CurrentCamera.CFrame.p
		for i = 1, #trailDots do
			local trailDotImage: ImageHandleAdornment = trailDots[i].DisplayModel:FindFirstChild("TrailDotImage")
			if trailDotImage then
				local distanceToCamera = (trailDots[i].DisplayModel.Position - cameraPos).Magnitude
				trailDotImage.Size = getTrailDotScale(distanceToCamera, TrailDotSize)
			end
		end
	end
	RunService:BindToRenderStep(reiszeTrailDotsUpdateName, Enum.RenderPriority.Camera.Value - 1, resizeTrailDots)

	local function removePath()
		removePathBeforePoint(#wayPoints)
	end

	return removePath, removePathBeforePoint
end

local lastFailureWaypoint = nil
function ClickToMoveDisplay.DisplayFailureWaypoint(position)
	if lastFailureWaypoint then
		lastFailureWaypoint:Hide()
	end
	local failureWaypoint = FailureWaypoint.new(position)
	lastFailureWaypoint = failureWaypoint
	coroutine.wrap(function()
		failureWaypoint:RunFailureTween()
		failureWaypoint:Destroy()
		failureWaypoint = nil
	end)()
end

function ClickToMoveDisplay.CreateEndWaypoint(position)
	return EndWaypoint.new(position)
end

function ClickToMoveDisplay.PlayFailureAnimation()
	local myHumanoid = findPlayerHumanoid()
	if myHumanoid then
		local animationTrack = getFailureAnimationTrack(myHumanoid)
		animationTrack:Play()
	end
end

function ClickToMoveDisplay.CancelFailureAnimation()
	if lastFailureAnimationTrack ~= nil and lastFailureAnimationTrack.IsPlaying then
		lastFailureAnimationTrack:Stop()
	end
end

function ClickToMoveDisplay.SetWaypointTexture(texture)
	TrailDotIcon = texture
	TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()
end

function ClickToMoveDisplay.GetWaypointTexture()
	return TrailDotIcon
end

function ClickToMoveDisplay.SetWaypointRadius(radius)
	TrailDotSize = Vector2.new(radius, radius)
	TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()
end

function ClickToMoveDisplay.GetWaypointRadius()
	return TrailDotSize.X
end

function ClickToMoveDisplay.SetEndWaypointTexture(texture)
	EndWaypointIcon = texture
	TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()
end

function ClickToMoveDisplay.GetEndWaypointTexture()
	return EndWaypointIcon
end

function ClickToMoveDisplay.SetWaypointsAlwaysOnTop(alwaysOnTop)
	WaypointsAlwaysOnTop = alwaysOnTop
	TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()
end

function ClickToMoveDisplay.GetWaypointsAlwaysOnTop()
	return WaypointsAlwaysOnTop
end
--!nonstrict
--[[
	-- Original By Kip Turner, Copyright Roblox 2014
	-- Updated by Garnold to utilize the new PathfindingService API, 2017
	-- 2018 PlayerScripts Update - AllYourBlox
--]]

--[[ Flags ]]
local FFlagUserExcludeNonCollidableForPathfindingSuccess, FFlagUserExcludeNonCollidableForPathfindingResult =
	pcall(function() return UserSettings():IsUserFeatureEnabled("UserExcludeNonCollidableForPathfinding") end)
local FFlagUserExcludeNonCollidableForPathfinding = FFlagUserExcludeNonCollidableForPathfindingSuccess and FFlagUserExcludeNonCollidableForPathfindingResult

local FFlagUserClickToMoveSupportAgentCanClimbSuccess, FFlagUserClickToMoveSupportAgentCanClimbResult =
	pcall(function() return UserSettings():IsUserFeatureEnabled("UserClickToMoveSupportAgentCanClimb2") end)
local FFlagUserClickToMoveSupportAgentCanClimb = FFlagUserClickToMoveSupportAgentCanClimbSuccess and FFlagUserClickToMoveSupportAgentCanClimbResult

--[[ Roblox Services ]]--
local UserInputService = game:GetService("UserInputService")
local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local DebrisService = game:GetService('Debris')
local StarterGui = game:GetService("StarterGui")
local Workspace = game:GetService("Workspace")
local CollectionService = game:GetService("CollectionService")
local GuiService = game:GetService("GuiService")

--[[ Configuration ]]
local ShowPath = true
local PlayFailureAnimation = true
local UseDirectPath = false
local UseDirectPathForVehicle = true
local AgentSizeIncreaseFactor = 1.0
local UnreachableWaypointTimeout = 8

--[[ Constants ]]--
local movementKeys = {
	[Enum.KeyCode.W] = true;
	[Enum.KeyCode.A] = true;
	[Enum.KeyCode.S] = true;
	[Enum.KeyCode.D] = true;
	[Enum.KeyCode.Up] = true;
	[Enum.KeyCode.Down] = true;
}

local Player = Players.LocalPlayer


local ZERO_VECTOR3 = Vector3.new(0,0,0)
local ALMOST_ZERO = 0.000001


--------------------------UTIL LIBRARY-------------------------------
local Utility = {}
do
	local function FindCharacterAncestor(part)
		if part then
			local humanoid = part:FindFirstChildOfClass("Humanoid")
			if humanoid then
				return part, humanoid
			else
				return FindCharacterAncestor(part.Parent)
			end
		end
	end
	Utility.FindCharacterAncestor = FindCharacterAncestor

	local function Raycast(ray, ignoreNonCollidable: boolean, ignoreList: {Model})
		ignoreList = ignoreList or {}
		local hitPart, hitPos, hitNorm, hitMat = Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
		if hitPart then
			if ignoreNonCollidable and hitPart.CanCollide == false then
				-- We always include character parts so a user can click on another character
				-- to walk to them.
				local _, humanoid = FindCharacterAncestor(hitPart)
				if humanoid == nil then
					table.insert(ignoreList, hitPart)
					return Raycast(ray, ignoreNonCollidable, ignoreList)
				end
			end
			return hitPart, hitPos, hitNorm, hitMat
		end
		return nil, nil
	end
	Utility.Raycast = Raycast
end

local humanoidCache = {}
local function findPlayerHumanoid(player: Player)
	local character = player and player.Character
	if character then
		local resultHumanoid = humanoidCache[player]
		if resultHumanoid and resultHumanoid.Parent == character then
			return resultHumanoid
		else
			humanoidCache[player] = nil -- Bust Old Cache
			local humanoid = character:FindFirstChildOfClass("Humanoid")
			if humanoid then
				humanoidCache[player] = humanoid
			end
			return humanoid
		end
	end
end

--------------------------CHARACTER CONTROL-------------------------------
local CurrentIgnoreList: {Model}
local CurrentIgnoreTag = nil

local TaggedInstanceAddedConnection: RBXScriptConnection? = nil
local TaggedInstanceRemovedConnection: RBXScriptConnection? = nil

local function GetCharacter(): Model
	return Player and Player.Character
end

local function UpdateIgnoreTag(newIgnoreTag)
	if newIgnoreTag == CurrentIgnoreTag then
		return
	end
	if TaggedInstanceAddedConnection then
		TaggedInstanceAddedConnection:Disconnect()
		TaggedInstanceAddedConnection = nil
	end
	if TaggedInstanceRemovedConnection then
		TaggedInstanceRemovedConnection:Disconnect()
		TaggedInstanceRemovedConnection = nil
	end
	CurrentIgnoreTag = newIgnoreTag
	CurrentIgnoreList = {GetCharacter()}
	if CurrentIgnoreTag ~= nil then
		local ignoreParts = CollectionService:GetTagged(CurrentIgnoreTag)
		for _, ignorePart in ipairs(ignoreParts) do
			table.insert(CurrentIgnoreList, ignorePart)
		end
		TaggedInstanceAddedConnection = CollectionService:GetInstanceAddedSignal(
			CurrentIgnoreTag):Connect(function(ignorePart)
			table.insert(CurrentIgnoreList, ignorePart)
		end)
		TaggedInstanceRemovedConnection = CollectionService:GetInstanceRemovedSignal(
			CurrentIgnoreTag):Connect(function(ignorePart)
			for i = 1, #CurrentIgnoreList do
				if CurrentIgnoreList[i] == ignorePart then
					CurrentIgnoreList[i] = CurrentIgnoreList[#CurrentIgnoreList]
					table.remove(CurrentIgnoreList)
					break
				end
			end
		end)
	end
end

local function getIgnoreList(): {Model}
	if CurrentIgnoreList then
		return CurrentIgnoreList
	end
	CurrentIgnoreList = {}
	assert(CurrentIgnoreList, "")
	table.insert(CurrentIgnoreList, GetCharacter())
	return CurrentIgnoreList
end

local function minV(a: Vector3, b: Vector3)
	return Vector3.new(math.min(a.X, b.X), math.min(a.Y, b.Y), math.min(a.Z, b.Z))
end
local function maxV(a, b)
	return Vector3.new(math.max(a.X, b.X), math.max(a.Y, b.Y), math.max(a.Z, b.Z))
end
local function getCollidableExtentsSize(character: Model?)
	if character == nil or character.PrimaryPart == nil then return end
	assert(character, "")
	assert(character.PrimaryPart, "")
	local toLocalCFrame = character.PrimaryPart.CFrame:Inverse()
	local min = Vector3.new(math.huge, math.huge, math.huge)
	local max = Vector3.new(-math.huge, -math.huge, -math.huge)
	for _,descendant in pairs(character:GetDescendants()) do
		if descendant:IsA('BasePart') and descendant.CanCollide then
			local localCFrame = toLocalCFrame * descendant.CFrame
			local size = Vector3.new(descendant.Size.X / 2, descendant.Size.Y / 2, descendant.Size.Z / 2)
			local vertices = {
				Vector3.new( size.X,  size.Y,  size.Z),
				Vector3.new( size.X,  size.Y, -size.Z),
				Vector3.new( size.X, -size.Y,  size.Z),
				Vector3.new( size.X, -size.Y, -size.Z),
				Vector3.new(-size.X,  size.Y,  size.Z),
				Vector3.new(-size.X,  size.Y, -size.Z),
				Vector3.new(-size.X, -size.Y,  size.Z),
				Vector3.new(-size.X, -size.Y, -size.Z)
			}
			for _,vertex in ipairs(vertices) do
				local v = localCFrame * vertex
				min = minV(min, v)
				max = maxV(max, v)
			end
		end
	end
	local r = max - min
	if r.X < 0 or r.Y < 0 or r.Z < 0 then return nil end
	return r
end

-----------------------------------PATHER--------------------------------------

local function Pather(endPoint, surfaceNormal, overrideUseDirectPath: boolean?)
	local this = {}

	local directPathForHumanoid
	local directPathForVehicle
	if overrideUseDirectPath ~= nil then
		directPathForHumanoid = overrideUseDirectPath
		directPathForVehicle = overrideUseDirectPath
	else
		directPathForHumanoid = UseDirectPath
		directPathForVehicle = UseDirectPathForVehicle
	end

	this.Cancelled = false
	this.Started = false

	this.Finished = Instance.new("BindableEvent")
	this.PathFailed = Instance.new("BindableEvent")

	this.PathComputing = false
	this.PathComputed = false

	this.OriginalTargetPoint = endPoint
	this.TargetPoint = endPoint
	this.TargetSurfaceNormal = surfaceNormal

	this.DiedConn = nil
	this.SeatedConn = nil
	this.BlockedConn = nil
	this.TeleportedConn = nil

	this.CurrentPoint = 0

	this.HumanoidOffsetFromPath = ZERO_VECTOR3

	this.CurrentWaypointPosition = nil
	this.CurrentWaypointPlaneNormal = ZERO_VECTOR3
	this.CurrentWaypointPlaneDistance = 0
	this.CurrentWaypointNeedsJump = false;

	this.CurrentHumanoidPosition = ZERO_VECTOR3
	this.CurrentHumanoidVelocity = 0 :: Vector3 | number

	this.NextActionMoveDirection = ZERO_VECTOR3
	this.NextActionJump = false

	this.Timeout = 0

	this.Humanoid = findPlayerHumanoid(Player)
	this.OriginPoint = nil
	this.AgentCanFollowPath = false
	this.DirectPath = false
	this.DirectPathRiseFirst = false

	this.stopTraverseFunc = nil :: (() -> ())?
	this.setPointFunc = nil :: ((number) -> ())?
	this.pointList = nil :: {PathWaypoint}?

	local rootPart: BasePart = this.Humanoid and this.Humanoid.RootPart
	if rootPart then
		-- Setup origin
		this.OriginPoint = rootPart.CFrame.Position

		-- Setup agent
		local agentRadius = 2
		local agentHeight = 5
		local agentCanJump = true

		local seat = this.Humanoid.SeatPart
		if seat and seat:IsA("VehicleSeat") then
			-- Humanoid is seated on a vehicle
			local vehicle = seat:FindFirstAncestorOfClass("Model")
			if vehicle then
				-- Make sure the PrimaryPart is set to the vehicle seat while we compute the extends.
				local tempPrimaryPart = vehicle.PrimaryPart
				vehicle.PrimaryPart = seat

				-- For now, only direct path
				if directPathForVehicle then
					local extents: Vector3 = vehicle:GetExtentsSize()
					agentRadius = AgentSizeIncreaseFactor * 0.5 * math.sqrt(extents.X * extents.X + extents.Z * extents.Z)
					agentHeight = AgentSizeIncreaseFactor * extents.Y
					agentCanJump = false
					this.AgentCanFollowPath = true
					this.DirectPath = directPathForVehicle
				end

				-- Reset PrimaryPart
				vehicle.PrimaryPart = tempPrimaryPart
			end
		else
			local extents: Vector3?
			if FFlagUserExcludeNonCollidableForPathfinding then
				local character: Model? = GetCharacter()
				if character ~= nil then
					extents = getCollidableExtentsSize(character)
				end
			end
			if extents == nil then
				extents = GetCharacter():GetExtentsSize()
			end
			assert(extents, "")
			agentRadius = AgentSizeIncreaseFactor * 0.5 * math.sqrt(extents.X * extents.X + extents.Z * extents.Z)
			agentHeight = AgentSizeIncreaseFactor * extents.Y
			agentCanJump = (this.Humanoid.JumpPower > 0)
			this.AgentCanFollowPath = true
			this.DirectPath = directPathForHumanoid :: boolean
			this.DirectPathRiseFirst = this.Humanoid.Sit
		end

		-- Build path object
		if FFlagUserClickToMoveSupportAgentCanClimb then
			this.pathResult = PathfindingService:CreatePath({AgentRadius = agentRadius, AgentHeight = agentHeight, AgentCanJump = agentCanJump, AgentCanClimb = true})
		else
			this.pathResult = PathfindingService:CreatePath({AgentRadius = agentRadius, AgentHeight = agentHeight, AgentCanJump = agentCanJump})
		end
	end

	function this:Cleanup()
		if this.stopTraverseFunc then
			this.stopTraverseFunc()
			this.stopTraverseFunc = nil
		end

		if this.BlockedConn then
			this.BlockedConn:Disconnect()
			this.BlockedConn = nil
		end

		if this.DiedConn then
			this.DiedConn:Disconnect()
			this.DiedConn = nil
		end

		if this.SeatedConn then
			this.SeatedConn:Disconnect()
			this.SeatedConn = nil
		end

		if this.TeleportedConn then
			this.TeleportedConn:Disconnect()
			this.TeleportedConn = nil
		end

		this.Started = false
	end

	function this:Cancel()
		this.Cancelled = true
		this:Cleanup()
	end

	function this:IsActive()
		return this.AgentCanFollowPath and this.Started and not this.Cancelled
	end

	function this:OnPathInterrupted()
		-- Stop moving
		this.Cancelled = true
		this:OnPointReached(false)
	end

	function this:ComputePath()
		if this.OriginPoint then
			if this.PathComputed or this.PathComputing then return end
			this.PathComputing = true
			if this.AgentCanFollowPath then
				if this.DirectPath then
					this.pointList = {
						PathWaypoint.new(this.OriginPoint, Enum.PathWaypointAction.Walk),
						PathWaypoint.new(this.TargetPoint, this.DirectPathRiseFirst and Enum.PathWaypointAction.Jump or Enum.PathWaypointAction.Walk)
					}
					this.PathComputed = true
				else
					this.pathResult:ComputeAsync(this.OriginPoint, this.TargetPoint)
					this.pointList = this.pathResult:GetWaypoints()
					this.BlockedConn = this.pathResult.Blocked:Connect(function(blockedIdx) this:OnPathBlocked(blockedIdx) end)
					this.PathComputed = this.pathResult.Status == Enum.PathStatus.Success
				end
			end
			this.PathComputing = false
		end
	end

	function this:IsValidPath()
		this:ComputePath()
		return this.PathComputed and this.AgentCanFollowPath
	end

	this.Recomputing = false
	function this:OnPathBlocked(blockedWaypointIdx)
		local pathBlocked = blockedWaypointIdx >= this.CurrentPoint
		if not pathBlocked or this.Recomputing then
			return
		end

		this.Recomputing = true

		if this.stopTraverseFunc then
			this.stopTraverseFunc()
			this.stopTraverseFunc = nil
		end

		this.OriginPoint = this.Humanoid.RootPart.CFrame.p

		this.pathResult:ComputeAsync(this.OriginPoint, this.TargetPoint)
		this.pointList = this.pathResult:GetWaypoints()
		if #this.pointList > 0 then
			this.HumanoidOffsetFromPath = this.pointList[1].Position - this.OriginPoint
		end
		this.PathComputed = this.pathResult.Status == Enum.PathStatus.Success

		if ShowPath then
			this.stopTraverseFunc, this.setPointFunc = ClickToMoveDisplay.CreatePathDisplay(this.pointList)
		end
		if this.PathComputed then
			this.CurrentPoint = 1 -- The first waypoint is always the start location. Skip it.
			this:OnPointReached(true) -- Move to first point
		else
			this.PathFailed:Fire()
			this:Cleanup()
		end

		this.Recomputing = false
	end

	function this:OnRenderStepped(dt: number)
		if this.Started and not this.Cancelled then
			-- Check for Timeout (if a waypoint is not reached within the delay, we fail)
			this.Timeout = this.Timeout + dt
			if this.Timeout > UnreachableWaypointTimeout then
				this:OnPointReached(false)
				return
			end

			-- Get Humanoid position and velocity
			this.CurrentHumanoidPosition = this.Humanoid.RootPart.Position + this.HumanoidOffsetFromPath
			this.CurrentHumanoidVelocity = this.Humanoid.RootPart.Velocity

			-- Check if it has reached some waypoints
			while this.Started and this:IsCurrentWaypointReached() do
				this:OnPointReached(true)
			end

			-- If still started, update actions
			if this.Started then
				-- Move action
				this.NextActionMoveDirection = this.CurrentWaypointPosition - this.CurrentHumanoidPosition
				if this.NextActionMoveDirection.Magnitude > ALMOST_ZERO then
					this.NextActionMoveDirection = this.NextActionMoveDirection.Unit
				else
					this.NextActionMoveDirection = ZERO_VECTOR3
				end
				-- Jump action
				if this.CurrentWaypointNeedsJump then
					this.NextActionJump = true
					this.CurrentWaypointNeedsJump = false	-- Request jump only once
				else
					this.NextActionJump = false
				end
			end
		end
	end

	function this:IsCurrentWaypointReached()
		local reached = false

		-- Check we do have a plane, if not, we consider the waypoint reached
		if this.CurrentWaypointPlaneNormal ~= ZERO_VECTOR3 then
			-- Compute distance of Humanoid from destination plane
			local dist = this.CurrentWaypointPlaneNormal:Dot(this.CurrentHumanoidPosition) - this.CurrentWaypointPlaneDistance
			-- Compute the component of the Humanoid velocity that is towards the plane
			local velocity = -this.CurrentWaypointPlaneNormal:Dot(this.CurrentHumanoidVelocity)
			-- Compute the threshold from the destination plane based on Humanoid velocity
			local threshold = math.max(1.0, 0.0625 * velocity)
			-- If we are less then threshold in front of the plane (between 0 and threshold) or if we are behing the plane (less then 0), we consider we reached it
			reached = dist < threshold
		else
			reached = true
		end

		if reached then
			this.CurrentWaypointPosition = nil
			this.CurrentWaypointPlaneNormal	= ZERO_VECTOR3
			this.CurrentWaypointPlaneDistance = 0
		end

		return reached
	end

	function this:OnPointReached(reached)

		if reached and not this.Cancelled then
			-- First, destroyed the current displayed waypoint
			if this.setPointFunc then
				this.setPointFunc(this.CurrentPoint)
			end

			local nextWaypointIdx = this.CurrentPoint + 1

			if nextWaypointIdx > #this.pointList then
				-- End of path reached
				if this.stopTraverseFunc then
					this.stopTraverseFunc()
				end
				this.Finished:Fire()
				this:Cleanup()
			else
				local currentWaypoint = this.pointList[this.CurrentPoint]
				local nextWaypoint = this.pointList[nextWaypointIdx]

				-- If airborne, only allow to keep moving
				-- if nextWaypoint.Action ~= Jump, or path mantains a direction
				-- Otherwise, wait until the humanoid gets to the ground
				local currentState = this.Humanoid:GetState()
				local isInAir = currentState == Enum.HumanoidStateType.FallingDown
					or currentState == Enum.HumanoidStateType.Freefall
					or currentState == Enum.HumanoidStateType.Jumping

				if isInAir then
					local shouldWaitForGround = nextWaypoint.Action == Enum.PathWaypointAction.Jump
					if not shouldWaitForGround and this.CurrentPoint > 1 then
						local prevWaypoint = this.pointList[this.CurrentPoint - 1]

						local prevDir = currentWaypoint.Position - prevWaypoint.Position
						local currDir = nextWaypoint.Position - currentWaypoint.Position

						local prevDirXZ = Vector2.new(prevDir.x, prevDir.z).Unit
						local currDirXZ = Vector2.new(currDir.x, currDir.z).Unit

						local THRESHOLD_COS = 0.996 -- ~cos(5 degrees)
						shouldWaitForGround = prevDirXZ:Dot(currDirXZ) < THRESHOLD_COS
					end

					if shouldWaitForGround then
						this.Humanoid.FreeFalling:Wait()

						-- Give time to the humanoid's state to change
						-- Otherwise, the jump flag in Humanoid
						-- will be reset by the state change
						wait(0.1)
					end
				end

				-- Move to the next point
				this:MoveToNextWayPoint(currentWaypoint, nextWaypoint, nextWaypointIdx)
			end
		else
			this.PathFailed:Fire()
			this:Cleanup()
		end
	end

	function this:MoveToNextWayPoint(currentWaypoint: PathWaypoint, nextWaypoint: PathWaypoint, nextWaypointIdx: number)
		-- Build next destination plane
		-- (plane normal is perpendicular to the y plane and is from next waypoint towards current one (provided the two waypoints are not at the same location))
		-- (plane location is at next waypoint)
		this.CurrentWaypointPlaneNormal = currentWaypoint.Position - nextWaypoint.Position

		-- plane normal isn't perpendicular to the y plane when climbing up
		if not FFlagUserClickToMoveSupportAgentCanClimb or (nextWaypoint.Label ~= "Climb") then
			this.CurrentWaypointPlaneNormal = Vector3.new(this.CurrentWaypointPlaneNormal.X, 0, this.CurrentWaypointPlaneNormal.Z)
		end
		if this.CurrentWaypointPlaneNormal.Magnitude > ALMOST_ZERO then
			this.CurrentWaypointPlaneNormal	= this.CurrentWaypointPlaneNormal.Unit
			this.CurrentWaypointPlaneDistance = this.CurrentWaypointPlaneNormal:Dot(nextWaypoint.Position)
		else
			-- Next waypoint is the same as current waypoint so no plane
			this.CurrentWaypointPlaneNormal	= ZERO_VECTOR3
			this.CurrentWaypointPlaneDistance = 0
		end

		-- Should we jump
		this.CurrentWaypointNeedsJump = nextWaypoint.Action == Enum.PathWaypointAction.Jump;

		-- Remember next waypoint position
		this.CurrentWaypointPosition = nextWaypoint.Position

		-- Move to next point
		this.CurrentPoint = nextWaypointIdx

		-- Finally reset Timeout
		this.Timeout = 0
	end

	function this:Start(overrideShowPath)
		if not this.AgentCanFollowPath then
			this.PathFailed:Fire()
			return
		end

		if this.Started then return end
		this.Started = true

		ClickToMoveDisplay.CancelFailureAnimation()

		if ShowPath then
			if overrideShowPath == nil or overrideShowPath then
				this.stopTraverseFunc, this.setPointFunc = ClickToMoveDisplay.CreatePathDisplay(this.pointList, this.OriginalTargetPoint)
			end
		end

		if #this.pointList > 0 then
			-- Determine the humanoid offset from the path's first point
			-- Offset of the first waypoint from the path's origin point
			this.HumanoidOffsetFromPath = Vector3.new(0, this.pointList[1].Position.Y - this.OriginPoint.Y, 0)

			-- As well as its current position and velocity
			this.CurrentHumanoidPosition = this.Humanoid.RootPart.Position + this.HumanoidOffsetFromPath
			this.CurrentHumanoidVelocity = this.Humanoid.RootPart.Velocity

			-- Connect to events
			this.SeatedConn = this.Humanoid.Seated:Connect(function(isSeated, seat) this:OnPathInterrupted() end)
			this.DiedConn = this.Humanoid.Died:Connect(function() this:OnPathInterrupted() end)
			this.TeleportedConn = this.Humanoid.RootPart:GetPropertyChangedSignal("CFrame"):Connect(function() this:OnPathInterrupted() end)

			-- Actually start
			this.CurrentPoint = 1 -- The first waypoint is always the start location. Skip it.
			this:OnPointReached(true) -- Move to first point
		else
			this.PathFailed:Fire()
			if this.stopTraverseFunc then
				this.stopTraverseFunc()
			end
		end
	end

	--We always raycast to the ground in the case that the user clicked a wall.
	local offsetPoint = this.TargetPoint + this.TargetSurfaceNormal*1.5
	local ray = Ray.new(offsetPoint, Vector3.new(0,-1,0)*50)
	local newHitPart, newHitPos = Workspace:FindPartOnRayWithIgnoreList(ray, getIgnoreList())
	if newHitPart then
		this.TargetPoint = newHitPos
	end
	this:ComputePath()

	return this
end

-------------------------------------------------------------------------

local function CheckAlive()
	local humanoid = findPlayerHumanoid(Player)
	return humanoid ~= nil and humanoid.Health > 0
end

local function GetEquippedTool(character: Model?)
	if character ~= nil then
		for _, child in pairs(character:GetChildren()) do
			if child:IsA('Tool') then
				return child
			end
		end
	end
end

local ExistingPather = nil
local ExistingIndicator = nil
local PathCompleteListener = nil
local PathFailedListener = nil

local function CleanupPath()
	if ExistingPather then
		ExistingPather:Cancel()
		ExistingPather = nil
	end
	if PathCompleteListener then
		PathCompleteListener:Disconnect()
		PathCompleteListener = nil
	end
	if PathFailedListener then
		PathFailedListener:Disconnect()
		PathFailedListener = nil
	end
	if ExistingIndicator then
		ExistingIndicator:Destroy()
	end
end

local function HandleMoveTo(thisPather, hitPt, hitChar, character, overrideShowPath)
	if ExistingPather then
		CleanupPath()
	end
	ExistingPather = thisPather
	thisPather:Start(overrideShowPath)

	PathCompleteListener = thisPather.Finished.Event:Connect(function()
		CleanupPath()
		if hitChar then
			local currentWeapon = GetEquippedTool(character)
			if currentWeapon then
				currentWeapon:Activate()
			end
		end
	end)
	PathFailedListener = thisPather.PathFailed.Event:Connect(function()
		CleanupPath()
		if overrideShowPath == nil or overrideShowPath then
			local shouldPlayFailureAnim = PlayFailureAnimation and not (ExistingPather and ExistingPather:IsActive())
			if shouldPlayFailureAnim then
				ClickToMoveDisplay.PlayFailureAnimation()
			end
			ClickToMoveDisplay.DisplayFailureWaypoint(hitPt)
		end
	end)
end

local function ShowPathFailedFeedback(hitPt)
	if ExistingPather and ExistingPather:IsActive() then
		ExistingPather:Cancel()
	end
	if PlayFailureAnimation then
		ClickToMoveDisplay.PlayFailureAnimation()
	end
	ClickToMoveDisplay.DisplayFailureWaypoint(hitPt)
end

function OnTap(tapPositions: {Vector3}, goToPoint: Vector3?, wasTouchTap: boolean?)
	-- Good to remember if this is the latest tap event
	local camera = Workspace.CurrentCamera
	local character = Player.Character

	if not CheckAlive() then return end

	-- This is a path tap position
	if #tapPositions == 1 or goToPoint then
		if camera then
			local unitRay = camera:ScreenPointToRay(tapPositions[1].X, tapPositions[1].Y)
			local ray = Ray.new(unitRay.Origin, unitRay.Direction*1000)

			local myHumanoid = findPlayerHumanoid(Player)
			local hitPart, hitPt, hitNormal = Utility.Raycast(ray, true, getIgnoreList())

			local hitChar, hitHumanoid = Utility.FindCharacterAncestor(hitPart)
			if wasTouchTap and hitHumanoid and StarterGui:GetCore("AvatarContextMenuEnabled") then
				local clickedPlayer = Players:GetPlayerFromCharacter(hitHumanoid.Parent)
				if clickedPlayer then
					CleanupPath()
					return
				end
			end
			if goToPoint then
				hitPt = goToPoint
				hitChar = nil
			end
			if hitPt and character then
				-- Clean up current path
				CleanupPath()
				local thisPather = Pather(hitPt, hitNormal)
				if thisPather:IsValidPath() then
					HandleMoveTo(thisPather, hitPt, hitChar, character)
				else
					-- Clean up
					thisPather:Cleanup()
					-- Feedback here for when we don't have a good path
					ShowPathFailedFeedback(hitPt)
				end
			end
		end
	elseif #tapPositions >= 2 then
		if camera then
			-- Do shoot
			local currentWeapon = GetEquippedTool(character)
			if currentWeapon then
				currentWeapon:Activate()
			end
		end
	end
end

local function DisconnectEvent(event)
	if event then
		event:Disconnect()
	end
end

--[[ The ClickToMove Controller Class ]]--
local ClickToMove={}

function ClickToMove.new(CONTROL_ACTION_PRIORITY)

end

function ClickToMove:DisconnectEvents()

end

function ClickToMove:OnTouchBegan(input, processed)
	if self.fingerTouches[input] == nil and not processed then
		self.numUnsunkTouches = self.numUnsunkTouches + 1
	end
	self.fingerTouches[input] = processed
end

function ClickToMove:OnTouchChanged(input, processed)
	if self.fingerTouches[input] == nil then
		self.fingerTouches[input] = processed
		if not processed then
			self.numUnsunkTouches = self.numUnsunkTouches + 1
		end
	end
end

function ClickToMove:OnTouchEnded(input, processed)
	if self.fingerTouches[input] ~= nil and self.fingerTouches[input] == false then
		self.numUnsunkTouches = self.numUnsunkTouches - 1
	end
	self.fingerTouches[input] = nil
end


function ClickToMove:OnCharacterAdded(character)
	self:DisconnectEvents()

	self.inputBeganConn = UserInputService.InputBegan:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchBegan(input, processed)
		end

		-- Cancel path when you use the keyboard controls if wasd is enabled.
		if self.wasdEnabled and processed == false and input.UserInputType == Enum.UserInputType.Keyboard
			and movementKeys[input.KeyCode] then
			CleanupPath()
			ClickToMoveDisplay.CancelFailureAnimation()
		end
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			self.mouse1DownTime = tick()
			self.mouse1DownPos = input.Position
		end
		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			self.mouse2DownTime = tick()
			self.mouse2DownPos = input.Position
		end
	end)

	self.inputChangedConn = UserInputService.InputChanged:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchChanged(input, processed)
		end
	end)

	self.inputEndedConn = UserInputService.InputEnded:Connect(function(input, processed)
		if input.UserInputType == Enum.UserInputType.Touch then
			self:OnTouchEnded(input, processed)
		end

		if input.UserInputType == Enum.UserInputType.MouseButton2 then
			self.mouse2UpTime = tick()
			local currPos: Vector3 = input.Position
			-- We allow click to move during path following or if there is no keyboard movement
			local allowed = ExistingPather or self.keyboardMoveVector.Magnitude <= 0
			if self.mouse2UpTime - self.mouse2DownTime < 0.25 and (currPos - self.mouse2DownPos).magnitude < 5 and allowed then
				local positions = {currPos}
				OnTap(positions)
			end
		end
	end)

	self.tapConn = UserInputService.TouchTap:Connect(function(touchPositions, processed)
		if not processed then
			OnTap(touchPositions, nil, true)
		end
	end)

	self.menuOpenedConnection = GuiService.MenuOpened:Connect(function()
		CleanupPath()
	end)

	local function OnCharacterChildAdded(child)
		if UserInputService.TouchEnabled then
			if child:IsA('Tool') then
				child.ManualActivationOnly = true
			end
		end
		if child:IsA('Humanoid') then
			DisconnectEvent(self.humanoidDiedConn)
			self.humanoidDiedConn = child.Died:Connect(function()
				if ExistingIndicator then
					DebrisService:AddItem(ExistingIndicator.Model, 1)
				end
			end)
		end
	end

	self.characterChildAddedConn = character.ChildAdded:Connect(function(child)
		OnCharacterChildAdded(child)
	end)
	self.characterChildRemovedConn = character.ChildRemoved:Connect(function(child)
		if UserInputService.TouchEnabled then
			if child:IsA('Tool') then
				child.ManualActivationOnly = false
			end
		end
	end)
	for _, child in pairs(character:GetChildren()) do
		OnCharacterChildAdded(child)
	end
end

function ClickToMove:Start()
	self:Enable(true)
end

function ClickToMove:Stop()
	self:Enable(false)
end

function ClickToMove:CleanupPath()
	CleanupPath()
end

function ClickToMove:Enable(enable: boolean, enableWASD: boolean, touchJumpController)
	if enable then
		if not self.running then
			if Player.Character then -- retro-listen
				self:OnCharacterAdded(Player.Character)
			end
			self.onCharacterAddedConn = Player.CharacterAdded:Connect(function(char)
				self:OnCharacterAdded(char)
			end)
			self.running = true
		end
		self.touchJumpController = touchJumpController
		if self.touchJumpController then
			self.touchJumpController:Enable(self.jumpEnabled)
		end
	else
		if self.running then
			self:DisconnectEvents()
			CleanupPath()
			-- Restore tool activation on shutdown
			if UserInputService.TouchEnabled then
				local character = Player.Character
				if character then
					for _, child in pairs(character:GetChildren()) do
						if child:IsA('Tool') then
							child.ManualActivationOnly = false
						end
					end
				end
			end
			self.running = false
		end
		if self.touchJumpController and not self.jumpEnabled then
			self.touchJumpController:Enable(true)
		end
		self.touchJumpController = nil
	end

	-- Extension for initializing Keyboard input as this class now derives from Keyboard
	if UserInputService.KeyboardEnabled and enable ~= self.enabled then

		self.forwardValue  = 0
		self.backwardValue = 0
		self.leftValue = 0
		self.rightValue = 0

		self.moveVector = ZERO_VECTOR3

		if enable then
			self:BindContextActions()
			self:ConnectFocusEventListeners()
		else
			self:UnbindContextActions()
			self:DisconnectFocusEventListeners()
		end
	end

	self.wasdEnabled = enable and enableWASD or false
	self.enabled = enable
end

function ClickToMove:OnRenderStepped(dt)
	-- Reset jump
	self.isJumping = false

	-- Handle Pather
	if ExistingPather then
		-- Let the Pather update
		ExistingPather:OnRenderStepped(dt)

		-- If we still have a Pather, set the resulting actions
		if ExistingPather then
			-- Setup move (NOT relative to camera)
			self.moveVector = ExistingPather.NextActionMoveDirection
			self.moveVectorIsCameraRelative = false

			-- Setup jump (but do NOT prevent the base Keayboard class from requesting jumps as well)
			if ExistingPather.NextActionJump then
				self.isJumping = true
			end
		else
			self.moveVector = self.keyboardMoveVector
			self.moveVectorIsCameraRelative = true
		end
	else
		self.moveVector = self.keyboardMoveVector
		self.moveVectorIsCameraRelative = true
	end

	-- Handle Keyboard's jump
	if self.jumpRequested then
		self.isJumping = true
	end
end

-- Overrides Keyboard:UpdateMovement(inputState) to conditionally consider self.wasdEnabled and let OnRenderStepped handle the movement
function ClickToMove:UpdateMovement(inputState)
	if inputState == Enum.UserInputState.Cancel then
		self.keyboardMoveVector = ZERO_VECTOR3
	elseif self.wasdEnabled then
		self.keyboardMoveVector = Vector3.new(self.leftValue + self.rightValue, 0, self.forwardValue + self.backwardValue)
	end
end

-- Overrides Keyboard:UpdateJump() because jump is handled in OnRenderStepped
function ClickToMove:UpdateJump()
	-- Nothing to do (handled in OnRenderStepped)
end

--Public developer facing functions
function ClickToMove:SetShowPath(value)
	ShowPath = value
end

function ClickToMove:GetShowPath()
	return ShowPath
end

function ClickToMove:SetWaypointTexture(texture)
	ClickToMoveDisplay.SetWaypointTexture(texture)
end

function ClickToMove:GetWaypointTexture()
	return ClickToMoveDisplay.GetWaypointTexture()
end

function ClickToMove:SetWaypointRadius(radius)
	ClickToMoveDisplay.SetWaypointRadius(radius)
end

function ClickToMove:GetWaypointRadius()
	return ClickToMoveDisplay.GetWaypointRadius()
end

function ClickToMove:SetEndWaypointTexture(texture)
	ClickToMoveDisplay.SetEndWaypointTexture(texture)
end

function ClickToMove:GetEndWaypointTexture()
	return ClickToMoveDisplay.GetEndWaypointTexture()
end

function ClickToMove:SetWaypointsAlwaysOnTop(alwaysOnTop)
	ClickToMoveDisplay.SetWaypointsAlwaysOnTop(alwaysOnTop)
end

function ClickToMove:GetWaypointsAlwaysOnTop()
	return ClickToMoveDisplay.GetWaypointsAlwaysOnTop()
end

function ClickToMove:SetFailureAnimationEnabled(enabled)
	PlayFailureAnimation = enabled
end

function ClickToMove:GetFailureAnimationEnabled()
	return PlayFailureAnimation
end

function ClickToMove:SetIgnoredPartsTag(tag)
	UpdateIgnoreTag(tag)
end

function ClickToMove:GetIgnoredPartsTag()
	return CurrentIgnoreTag
end

function ClickToMove:SetUseDirectPath(directPath)
	UseDirectPath = directPath
end

function ClickToMove:GetUseDirectPath()
	return UseDirectPath
end

function ClickToMove:SetAgentSizeIncreaseFactor(increaseFactorPercent: number)
	AgentSizeIncreaseFactor = 1.0 + (increaseFactorPercent / 100.0)
end

function ClickToMove:GetAgentSizeIncreaseFactor()
	return (AgentSizeIncreaseFactor - 1.0) * 100.0
end

function ClickToMove:SetUnreachableWaypointTimeout(timeoutInSec)
	UnreachableWaypointTimeout = timeoutInSec
end

function ClickToMove:GetUnreachableWaypointTimeout()
	return UnreachableWaypointTimeout
end

function ClickToMove:SetUserJumpEnabled(jumpEnabled)
	self.jumpEnabled = jumpEnabled
	if self.touchJumpController then
		self.touchJumpController:Enable(jumpEnabled)
	end
end

function ClickToMove:GetUserJumpEnabled()
	return self.jumpEnabled
end

function ClickToMove:MoveTo(position, showPath, useDirectPath)
	local character = Player.Character
	if character == nil then
		return false
	end
	local thisPather = Pather(position, Vector3.new(0, 1, 0), useDirectPath)
	if thisPather and thisPather:IsValidPath() then
		HandleMoveTo(thisPather, position, nil, character, showPath)
		return true
	end
	return false
end



local settings = {refill_at=0, refill_end=60, deliver_at=24, stay_in_kitchen=true}
local doCashier,doBoxer,doCook,doSupplier,doDelivery = true,true,true,true,true
if readfile then
	pcall(function()
		local new = game:GetService("HttpService"):JSONDecode(readfile("PizzaFarm.txt"))
		--corruption?
		local doOverwrite=false
		for k,v in pairs(new) do
			if settings[k]==nil then
				doOverwrite=true
				new[k]=nil
			end
		end
		for k,v in pairs(settings) do
			if new[k]==nil then
				doOverwrite=true
				new[k]=v
			end
		end
		--use input
		if doOverwrite then
			warn("Settings overwritten")
			writefile("PizzaFarm.txt",game:GetService("HttpService"):JSONEncode(new))
		end
		settings = new
	end)
end

if getconnections then
	for _,c in next,getconnections(game:GetService("ScriptContext").Error) do
		c:Disable()
	end
end

local player = game:GetService("Players").LocalPlayer
local ffc = game.FindFirstChild
local RNG = Random.new()
local network
local character,root,humanoid
do
	local reg = (getreg or debug.getregistry)()
	for i=1,#reg do
		local f = reg[i]
		if type(f)=="function" then
			for k,v in next,getupvalues(f) do
				if typeof(v)=="Instance" then
					if v.Name=="CashOut" then
						setupvalue(f,k,{MouseButton1Click={wait=function()end,Wait=function()end}})
					elseif v.Name=="StickerName" then
						setupvalue(f,k,nil)
					end
				end
			end
			if tostring(getfenv(f).script) == "Music" then
				local consts = getconstants(f)
				local loc=false
				for ci,c in next,consts do
					if c == "location changed" then
						loc=true
					elseif loc and c == "SendData" then
						setconstant(f,ci,"ExplodeString")
						break
					end
				end
			end
		elseif type(f)=="table" and rawget(f,"FireServer") and rawget(f,"BindEvents") then
			network = f
		end
	end
end
assert(network,"failed to find network")
--//gui
Create = function(class,parent,props)
	local new = Instance.new(class)
	for k,v in next,props do
		new[k]=v
	end
	new.Parent = parent
	return new
end
gui=Create("ScreenGui",game.CoreGui,{Name="Farm", ZIndexBehavior="Sibling"})
main=Create("Frame",gui,{Name="main", Draggable=true, Active=true, Size=UDim2.new(0,350,0,100), Position=UDim2.new(.335,0,0.02,0), BackgroundColor3=Color3.new(0.098,0.098,0.098)})
topbar=Create("Frame",main,{Name="topbar", Size=UDim2.new(1,0,0.15,0), BackgroundColor3=Color3.new(0.255,0.255,0.255)})
closeBtn=Create("TextButton",topbar,{Name="closeBtn", TextWrapped=true, Size=UDim2.new(0.03,0,1,0), TextColor3=Color3.new(1,1,1), Text="X", BackgroundTransparency=1, 
	Font="GothamSemibold", Position=UDim2.new(0.96,0,0,0), TextSize=14, TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
titleLbl=Create("TextLabel",topbar,{Name="titleLbl", TextWrapped=true, Size=UDim2.new(0.5,0,1,0), Text="Pizza Factory", TextSize=14, Font="GothamSemibold", 
	BackgroundTransparency=1, Position=UDim2.new(0.25,0,0,0), TextColor3=Color3.new(1,1,1), BackgroundColor3=Color3.new(1,1,1)})
saveBtn=Create("ImageButton",topbar,{Name="saveBtn", Image="rbxassetid://55687833", Size=UDim2.new(0.05,0,1,0), Position=UDim2.new(0.01,0,0,0), BackgroundTransparency=1, BackgroundColor3=Color3.new(), Visible=writefile~=nil})
settings_1=Create("Frame",main,{Name="settings", BackgroundTransparency=1, Size=UDim2.new(0.97,0,0.75,0), Position=UDim2.new(0.025,0,0.2,0), BackgroundColor3=Color3.new(1,1,1)})
Layout=Create("UIGridLayout",settings_1,{VerticalAlignment="Center", SortOrder="LayoutOrder", HorizontalAlignment="Center", CellPadding=UDim2.new(0.01,0,0.1,0), CellSize=UDim2.new(0.325,0,0.26,0)})
cashier=Create("Frame",settings_1,{Name="cashier", LayoutOrder=4, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
Label=Create("TextLabel",cashier,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Cashier", TextSize=14, TextXAlignment="Left", Font="SourceSans", 
	BackgroundTransparency=1, Position=UDim2.new(0.4,0,0,0), TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
cashierBtn=Create("ImageButton",cashier,{Name="cashierBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.38,0,1,0), BackgroundColor3=Color3.new(0.392,0.392,0.392)})
cashierSlider=Create("Frame",cashierBtn,{Name="slider", Size=UDim2.new(0.5,-4,1,-4), Position=UDim2.new(doCashier and 0.5 or 0,2,0,2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
kitchen=Create("Frame",settings_1,{Name="kitchen", LayoutOrder=9, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
Label_2=Create("TextLabel",kitchen,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Deliver At:", TextSize=14, TextXAlignment="Right", Font="SourceSans", 
	BackgroundTransparency=1, TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
deliverAtBox=Create("TextBox",kitchen,{Name="deliverAtBox", TextWrapped=true, Size=UDim2.new(0.25,0,1,0), Text=tostring(settings.deliver_at), TextSize=50, TextColor3=Color3.new(), 
	Font="Code", Position=UDim2.new(0.62,0,0,0), TextScaled=true, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
refillEnd=Create("Frame",settings_1,{Name="refillEnd", LayoutOrder=8, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
refillEndBox=Create("TextBox",refillEnd,{Name="refillEndBox", TextWrapped=true, Size=UDim2.new(0.25,0,1,0), Text=tostring(settings.refill_end), TextSize=50, TextColor3=Color3.new(), 
	Font="Code", Position=UDim2.new(0.62,0,0,0), TextScaled=true, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
Label_3=Create("TextLabel",refillEnd,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Refill End:", TextSize=14, TextXAlignment="Right", Font="SourceSans", 
	BackgroundTransparency=1, TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
refillAt=Create("Frame",settings_1,{Name="refillAt", LayoutOrder=7, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
Label_4=Create("TextLabel",refillAt,{TextWrapped=true, Size=UDim2.new(0.5,0,1,0), Text="Refill At:", TextSize=14, TextXAlignment="Right", Font="SourceSans", 
	BackgroundTransparency=1, TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
refillAtBox=Create("TextBox",refillAt,{Name="refillAtBox", TextWrapped=true, Size=UDim2.new(0.25,0,1,0), Text=tostring(settings.refill_at), TextSize=50, TextColor3=Color3.new(), 
	Font="Code", Position=UDim2.new(0.52,0,0,0), TextScaled=true, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
supplier=Create("Frame",settings_1,{Name="supplier", LayoutOrder=6, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
Label_5=Create("TextLabel",supplier,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Supplier", TextSize=14, TextXAlignment="Left", Font="SourceSans", 
	BackgroundTransparency=1, Position=UDim2.new(0.4,0,0,0), TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
supplierBtn=Create("ImageButton",supplier,{Name="supplierBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.38,0,1,0), BackgroundColor3=Color3.new(0.392,0.392,0.392)})
supplierSlider=Create("Frame",supplierBtn,{Name="slider", Size=UDim2.new(0.5,-4,1,-4), Position=UDim2.new(doSupplier and 0.5 or 0,2,0,2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
delivery=Create("Frame",settings_1,{Name="delivery", LayoutOrder=5, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
Label_6=Create("TextLabel",delivery,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Delivery", TextSize=14, TextXAlignment="Left", Font="SourceSans", 
	BackgroundTransparency=1, Position=UDim2.new(0.4,0,0,0), TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
deliveryBtn=Create("ImageButton",delivery,{Name="deliveryBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.38,0,1,0), BackgroundColor3=Color3.new(0.392,0.392,0.392)})
deliverySlider=Create("Frame",deliveryBtn,{Name="slider", Size=UDim2.new(0.5,-4,1,-4), Position=UDim2.new(doDelivery and 0.5 or 0,2,0,2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
boxer=Create("Frame",settings_1,{Name="boxer", LayoutOrder=2, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
boxerLbl=Create("TextLabel",boxer,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Boxer", TextSize=14, TextXAlignment="Left", Font="SourceSans", 
	BackgroundTransparency=1, Position=UDim2.new(0.4,0,0,0), TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
boxerBtn=Create("ImageButton",boxer,{Name="boxerBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.38,0,1,0), BackgroundColor3=Color3.new(0.392,0.392,0.392)})
boxerSlider=Create("Frame",boxerBtn,{Name="slider", Size=UDim2.new(0.5,-4,1,-4), Position=UDim2.new(doBoxer and 0.5 or 0,2,0,2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
cook=Create("Frame",settings_1,{Name="cook", LayoutOrder=3, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
cookLbl=Create("TextLabel",cook,{TextWrapped=true, Size=UDim2.new(0.6,0,1,0), Text="Cook", TextSize=14, TextXAlignment="Left", Font="SourceSans", 
	BackgroundTransparency=1, Position=UDim2.new(0.4,0,0,0), TextColor3=Color3.new(1,1,1), TextScaled=true, BackgroundColor3=Color3.new(1,1,1)})
cookBtn=Create("ImageButton",cook,{Name="cookBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.38,0,1,0), BackgroundColor3=Color3.new(0.392,0.392,0.392)})
cookSlider=Create("Frame",cookBtn,{Name="slider", Size=UDim2.new(0.5,-4,1,-4), Position=UDim2.new(doCook and 0.5 or 0,2,0,2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
toggleAll=Create("Frame",settings_1,{Name="toggleAll", LayoutOrder=1, BackgroundTransparency=1, Size=UDim2.new(0,100,0,100), BackgroundColor3=Color3.new(1,1,1)})
switch=Create("Frame",toggleAll,{Name="switch", BackgroundTransparency=1, Size=UDim2.new(0.75,0,1,0), BackgroundColor3=Color3.new(1,1,1)})
allOffBtn=Create("ImageButton",switch,{Name="allOffBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.5,0,1,0), BackgroundColor3=Color3.new(0.235,0.235,0.235)})
allOnBtn=Create("ImageButton",switch,{Name="allOnBtn", ImageTransparency=1, BorderSizePixel=0, Size=UDim2.new(0.5,0,1,0), Position=UDim2.new(0.5,0,0,0), BackgroundColor3=Color3.new(0.333,0.333,0.333)})
toggleAllSlider=Create("Frame",switch,{Name="slider", Size=UDim2.new(0.1,0,1,4), Position=UDim2.new(0.45,0,0,-2), BorderSizePixel=0, BackgroundColor3=Color3.new(0.784,0.784,0.784)})
messageLbl=Create("TextLabel",topbar,{Name="messageLbl", Size=UDim2.new(0.5,0,1,0), Text="Saved.", TextSize=14, Font="GothamSemibold", BackgroundTransparency=1, 
	Position=UDim2.new(0.07,0,0,0), TextColor3=Color3.new(1,1,1), Visible=false, TextXAlignment="Left"})
camframe=Create("Frame",gui,{Name="camframe", BackgroundTransparency=1, Size=UDim2.new(0,120,0,40), Position=UDim2.new(0.5,-320,0,-38), BackgroundColor3=Color3.new(0.118,0.118,0.118)})
rightCamBtn=Create("ImageButton",camframe,{Name="rightCamBtn", Image="rbxassetid://144168163", Size=UDim2.new(0.333,0,1,0), Rotation=180, Position=UDim2.new(0.666,0,0,0), BackgroundTransparency=1, 
	BackgroundColor3=Color3.new(1,1,1)})
leftCamBtn=Create("ImageButton",camframe,{Name="leftCamBtn", Image="rbxassetid://144168163", Size=UDim2.new(0.333,0,1,0), BackgroundTransparency=1, BackgroundColor3=Color3.new(1,1,1)})
centerCamBtn=Create("ImageButton",camframe,{Name="centerCamBtn", Image="rbxassetid://58282192", Size=UDim2.new(0.333,0,1,0), Position=UDim2.new(0.333,0,0,0), BackgroundTransparency=1, BackgroundColor3=Color3.new(1,1,1)})
creditLbl=Create("TextLabel",main,{Position=UDim2.new(0,0,1,5),Size=UDim2.new(0,100,0,15),BackgroundTransparency=1,TextColor3=Color3.new(1,1,1),Text="by sirelKilla",TextScaled=true,TextStrokeTransparency=.8})

local function toggleCashier(bool)
	if bool~=nil then
		doCashier=bool
	else
		doCashier = not doCashier
	end
	cashierSlider:TweenPosition(UDim2.new(doCashier and 0.5 or 0,2,0,2),nil,"Sine",0.1,true)
end
local function toggleCook(bool)
	if bool~=nil then
		doCook=bool
	else
		doCook = not doCook
	end
	cookSlider:TweenPosition(UDim2.new(doCook and 0.5 or 0,2,0,2),nil,"Sine",0.1,true)
end
local function toggleBoxer(bool)
	if bool~=nil then
		doBoxer=bool
	else
		doBoxer = not doBoxer
	end
	boxerSlider:TweenPosition(UDim2.new(doBoxer and 0.5 or 0,2,0,2),nil,"Sine",0.1,true)
end
local function toggleDelivery(bool)
	if bool~=nil then
		doDelivery=bool
	else
		doDelivery = not doDelivery
	end
	deliverySlider:TweenPosition(UDim2.new(doDelivery and 0.5 or 0,2,0,2),nil,"Sine",0.1,true)
end
local function toggleSupplier(bool)
	if bool~=nil then
		doSupplier=bool
	else
		doSupplier = not doSupplier
	end
	supplierSlider:TweenPosition(UDim2.new(doSupplier and 0.5 or 0,2,0,2),nil,"Sine",0.1,true)
end
cashierBtn.MouseButton1Click:Connect(toggleCashier)
cookBtn.MouseButton1Click:Connect(toggleCook)
boxerBtn.MouseButton1Click:Connect(toggleBoxer)
deliveryBtn.MouseButton1Click:Connect(toggleDelivery)
supplierBtn.MouseButton1Click:Connect(toggleSupplier)
allOffBtn.InputBegan:Connect(function()
	if game:GetService("UserInputService"):IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
		toggleCashier(false)
		toggleCook(false)
		toggleBoxer(false)
		toggleDelivery(false)
		toggleSupplier(false)
		toggleAllSlider:TweenPosition(UDim2.new(0,0,0,-2),nil,"Sine",0.1,true)
		wait(1)
		if toggleAllSlider.Position.X.Scale<.01 then
			toggleAllSlider:TweenPosition(UDim2.new(0.45,0,0,-2),nil,"Sine",0.1,true)
		end
	end
end)
allOnBtn.InputBegan:Connect(function()
	if game:GetService("UserInputService"):IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
		toggleCashier(true)
		toggleCook(true)
		toggleBoxer(true)
		toggleDelivery(true)
		toggleSupplier(true)
		toggleAllSlider:TweenPosition(UDim2.new(0.9,0,0,-2),nil,"Sine",0.1,true)
		wait(1)
		if toggleAllSlider.Position.X.Scale>.88 then
			toggleAllSlider:TweenPosition(UDim2.new(0.45,0,0,-2),nil,"Sine",0.1,true)
		end
	end
end)
local oldRefillAt=refillAtBox.Text
refillAtBox:GetPropertyChangedSignal("Text"):Connect(function()
	if #refillAtBox.Text>2 or refillAtBox.Text:match("%D") then
		refillAtBox.Text = oldRefillAt
	end
	oldRefillAt = refillAtBox.Text
end)
refillAtBox.FocusLost:Connect(function()
	if tonumber(refillAtBox.Text) then
		settings.refill_at=tonumber(refillAtBox.Text)
	end
	refillAtBox.Text=tostring(settings.refill_at)
end)
local oldRefillEnd=refillEndBox.Text
refillEndBox:GetPropertyChangedSignal("Text"):Connect(function()
	if #refillEndBox.Text>2 or refillEndBox.Text:match("%D") then
		refillEndBox.Text = oldRefillEnd
	end
	oldRefillEnd = refillEndBox.Text
end)
refillEndBox.FocusLost:Connect(function()
	if tonumber(refillEndBox.Text) then
		settings.refill_end=tonumber(refillEndBox.Text)
	end
	refillEndBox.Text=tostring(settings.refill_end)
end)
local oldDeliverAt=deliverAtBox.Text
deliverAtBox:GetPropertyChangedSignal("Text"):Connect(function()
	if #deliverAtBox.Text>2 or deliverAtBox.Text:match("%D") then
		deliverAtBox.Text = oldDeliverAt
	end
	oldDeliverAt = deliverAtBox.Text
end)
deliverAtBox.FocusLost:Connect(function()
	if tonumber(deliverAtBox.Text) then
		settings.deliver_at=tonumber(deliverAtBox.Text)
	end
	deliverAtBox.Text=tostring(settings.deliver_at)
end)
closeBtn.MouseButton1Click:Connect(function()
	gui:Destroy()
	doCashier,doBoxer,doCook,doSupplier,doDelivery = false,false,false,false,false
end)
closeBtn.MouseEnter:Connect(function() closeBtn.TextColor3=Color3.new(.9,0,0) end)
closeBtn.MouseLeave:Connect(function() closeBtn.TextColor3=Color3.new(1,1,1) end)
saveBtn.MouseButton1Click:Connect(function()
	if writefile and messageLbl.Visible==false then
		writefile("PizzaFarm.txt",game:GetService("HttpService"):JSONEncode(settings))
		messageLbl.Visible=true
		wait(2)
		messageLbl.Visible=false
	end
end)
local cameraArray = {CFrame.new(23,14,65,0.629,0.386,-0.674,-0,0.867,0.497,0.777,-0.313,0.545),CFrame.new(39,15,83,-0.571,0.392,-0.720,-0,0.878,0.478,0.820,0.273,-0.502),CFrame.new(40,20,-38,-0.801,-0.229,0.552,-0,0.923,0.384,-0.598,0.307,-0.739),CFrame.new(51,15,-25,-0.707,0.338,-0.620,0,0.878,0.478,0.707,0.338,-0.620),CFrame.new(47,12,21,0.026,0.323,-0.945,-0,0.946,0.323,0.999,-0.008,0.024)}
local cameraIndex = 0
centerCamBtn.MouseButton1Click:Connect(function()
	cameraIndex = 0
	workspace.CurrentCamera.CameraType = "Custom"
end)
leftCamBtn.MouseButton1Click:Connect(function()
	cameraIndex = cameraIndex - 1
	if cameraIndex < 0 then
		cameraIndex = #cameraArray
	end
	if cameraIndex == 0 then
		workspace.CurrentCamera.CameraType="Custom"
	else
		local cf = cameraArray[cameraIndex]
		workspace.CurrentCamera.CameraType="Scriptable"
		workspace.CurrentCamera:Interpolate(cf,cf+cf.lookVector*10,0.5)
	end
end)
rightCamBtn.MouseButton1Click:Connect(function()
	cameraIndex = cameraIndex + 1
	if cameraIndex > #cameraArray then
		cameraIndex = 0
		workspace.CurrentCamera.CameraType="Custom"
	else
		local cf = cameraArray[cameraIndex]
		workspace.CurrentCamera.CameraType="Scriptable"
		workspace.CurrentCamera:Interpolate(cf,cf+cf.lookVector*10,0.5)
	end
end)

--//subroutines
local supplyCounts = {TomatoSauce=99,Cheese=99,Sausage=99,Pepperoni=99,Dough=99,Box=99,Dew=99}
for name in pairs(supplyCounts) do
	local lbl = workspace.SupplyCounters.Model[name=="Dew" and "CounterMountainDew" or "Counter"..name].a.SG.Counter
	supplyCounts[name]=tonumber(lbl.Text)
	lbl.Changed:Connect(function()
		supplyCounts[name]=tonumber(lbl.Text)
	end)
end

local function FindFirstCustomer()
	local children = workspace.Customers:GetChildren()
	for i=1,#children do
		local c = children[i]
		if ffc(c,"Head") and ffc(c,"Humanoid") and c.Head.CFrame.Z<102 and ffc(c.Head,"Dialog") and ffc(c.Head.Dialog,"Correct") and ((c.Humanoid.SeatPart and c.Humanoid.SeatPart.Anchored) or (c.Humanoid.SeatPart==nil and (c.Head.Velocity.Z^2)^.5<.0001)) then
			local dialog = c.Head.Dialog.Correct.ResponseDialog or ''
			local order = "MountainDew"
			if dialog:sub(-8)=="instead." then
				dialog = dialog:sub(-30)
			end
			if dialog:find("pepperoni",1,true) then
				order = "PepperoniPizza"
			elseif dialog:find("sausage",1,true) then
				order = "SausagePizza"
			elseif dialog:find("cheese",1,true) then
				order = "CheesePizza"
			end
			return c,order
		end
	end
end

local boxPtick=0
local boxDtick=0
local function FindBoxes()
	local c,o,f
	local children = workspace.AllBox:GetChildren()
	for i=1,#children do
		local b = children[i]
		if ffc(b,"HasPizzaInside") or ffc(b,"Pizza") then
			if c==nil and b.Name=="BoxClosed" and b.Anchored==false and not b.HasPizzaInside.Value then
				c=b
			elseif o==nil and b.Name=="BoxOpen" and b.Anchored==false and not b.Pizza.Value then
				o=b
			elseif f==nil and (b.Name=="BoxOpen" and b.Pizza.Value) or (b.Name=="BoxClosed" and b.HasPizzaInside.Value) then
				f=b
			end
			if c and o and f then
				return c,o,f
			end
		end
	end
	return c,o,f
end
local function FindBoxingFoods()
	local p,d
	local children = workspace.BoxingRoom:GetChildren()
	for i=1,#children do
		local f = children[i]
		if not f.Anchored then
			if p==nil and f.Name=="Pizza" then
				p=f
			elseif d==nil and f.Name=="Dew" then
				d=f
			end
			if p and d then
				return p,d
			end
		end
	end
	return p,d
end

local orderDict={["3540529228"]="Cheese",["3540530535"]="Sausage",["3540529917"]="Pepperoni",["2512571151"]="Dew",["2512441325"]="Dew"}
local cookingDict = {Cheese=0,Sausage=0,Pepperoni=0,Dew=0}
local cookPtick=0
local cookDtick=0
local cookWarned=false
local boxerWarned=false
local function getOrders()
	local orders={}
	local tempCookingDict = {}
	for i,v in pairs(cookingDict) do tempCookingDict[i]=v end
	local children = workspace.Orders:GetChildren()
	for i=1,#children do
		local o = orderDict[children[i].SG.ImageLabel.Image:match("%d+$")]
		if o then
			if tempCookingDict[o]>0 then
				--ignores oven pizzas, so new orders are priority
				tempCookingDict[o]=tempCookingDict[o]-1
			elseif (o=="Dew" and #workspace.AllMountainDew:GetChildren()>0) or (supplyCounts[o]>0 and supplyCounts.TomatoSauce>0 and supplyCounts.Cheese>0) then
				--need supplies
				orders[#orders+1]=o
			end
		end
	end
	return orders
end
local function FindFirstDew()
	local children = workspace.AllMountainDew:GetChildren()
	for i=1,#children do
		local d = children[i]
		if (ffc(d,"IsBurned")==nil or d.IsBurned.Value==false) and not d.Anchored then
			return d
		end
	end
end
local function FindBadDew()
	local children = workspace.AllMountainDew:GetChildren()
	for i=1,#children do
		local d = children[i]
		if (ffc(d,"IsBurned")==nil or d.IsBurned.Value==false) and d.Position.X > 53 and d.Position.Z > 50 and not d.Anchored then
			return d
		end
	end
end
local function FindDoughAndWithout(str)
	local goodraw,p,raw,trash
	local children = workspace.AllDough:GetChildren()
	for i = #children, 2, -1 do --shuffle
		local j = RNG:NextInteger(1, i)
		children[j], children[i] = children[i], children[j]
	end
	for i=1,#children do
		local d = children[i]
		if d.Anchored==false and #d:GetChildren()>9 then
			if d.IsBurned.Value or d.HasBugs.Value or d.Cold.Value or (d.BrickColor.Name=="Bright orange" and ffc(d,"XBillboard")) then
				if trash==nil and d.Position.Y > 0 and ((d.Position*Vector3.new(1,0,1))-Vector3.new(47.90, 0, 72.49)).Magnitude > 1 then
					trash=d
				end
			elseif p==nil and d.BrickColor.Name=="Bright orange" then
				p=d
			elseif goodraw==nil and d.Position.X<55 and d.BrickColor.Name=="Brick yellow" and ((str and not ffc(d.SG.Frame,str)) or (str==nil and ffc(d.SG.Frame,"Sausage")==nil and ffc(d.SG.Frame,"Pepperoni")==nil)) then
				--prefers flat
				if d.Mesh.Scale.Y<1.1 then
					goodraw=d
				else
					raw=d
				end
			end
			if goodraw and p and trash then
				return goodraw,p,trash
			end
		end
	end
	return goodraw or raw,p,trash
end
local function getOvenNear(pos)
	local children = workspace.Ovens:GetChildren()
	for i=1,#children do
		if ffc(children[i],"Bottom") and (children[i].Bottom.Position-pos).magnitude < 1.5 then
			return children[i]
		end
	end
end
local function getDoughNear(pos)
	local children = workspace.AllDough:GetChildren()
	for i=1,#children do
		if (children[i].Position-pos).magnitude < 1.5 then
			return children[i]
		end
	end
end
local function isFullyOpen(oven)
	return oven.IsOpen.Value==true and (oven.Door.Meter.RotVelocity.Z^2)^.5<.0001
end

local bcolorToSupply = {["Dark orange"]="Sausage",["Bright blue"]="Pepperoni",["Bright yellow"]="Cheese",["Bright red"]="TomatoSauce",["Dark green"]="Dew",["Brick yellow"]="Dough",["Light stone grey"]="Box",["Really black"]="Dew"}
local supplyButtons = {}
for i,v in ipairs(workspace.SupplyButtons:GetChildren()) do
	supplyButtons[i] = v.Unpressed
end
table.sort(supplyButtons,function(a,b) return a.Position.X < b.Position.X end)
local delTick = 0
local function FindAllDeliveryTools(parent)
	local t = {}
	local children = parent:GetChildren()
	for i=1,#children do
		local v = children[i]
		if v.ClassName=="Tool" and v.Name:match("^%u%d$") and ffc(v,"Handle") and ffc(v,"House") and (parent~=workspace or (v.Handle.Position-Vector3.new(54.45, 4.02, -16.56)).Magnitude < 30) then
			t[#t+1] = v
		end
	end
	return t
end
local function getHousePart(address)
	local houses = workspace.Houses:GetChildren()
	for i=1,#houses do
		local h = houses[i]
		if ffc(h,"Address") and h.Address.Value==address and ffc(h,"GivePizza",true) then
			return ffc(h,"GivePizza",true)
		end
	end
end
local dance=Instance.new("Animation")
pcall(function()
	dance.AnimationId="http://www.roblox.com/asset/?id=182436842"
	dance=player.Character:FindFirstChildWhichIsA("Humanoid"):LoadAnimation(dance)
end)
function newdance()
	pcall(function()
		dance=Instance.new("Animation")
		dance.AnimationId="http://www.roblox.com/asset/?id=182436842"
		dance=player.Character:FindFirstChildWhichIsA("Humanoid"):LoadAnimation(dance)
	end)
end
local function onCharacterAdded(char)
	if not char then return end
	wait(0.3)
	character=char
	newdance()
	root = character:WaitForChild("HumanoidRootPart")
	humanoid = character:WaitForChild("Humanoid")
	humanoid:SetStateEnabled("FallingDown",false)
end
onCharacterAdded(player.Character or player.CharacterAdded:Wait())
player.CharacterAdded:Connect(onCharacterAdded)
local noclipppp=false
game:GetService("RunService").Stepped:Connect(function()
	if noclipppp then
		pcall(function()
			for i,_ in next,player.Character:GetDescendants() do
				if _:IsA("BasePart") then
					_.CanCollide=false
				end
			end
		end)
	end
end)
local function smoothTP2(cf)
	local cf0 = (cf-cf.p) + root.Position + Vector3.new(0,-7,0)
	local diff = cf.p - root.Position
	local oldg = workspace.Gravity
	workspace.Gravity = 0
	noclipppp=true
	dance:Play()
	ClickToMove:MoveTo(cf.Position,true,true)
	for i=0,diff.Magnitude,2 do
		humanoid.Sit=false
		dance:AdjustSpeed(1+i*1.2)
		root.CFrame = cf0 + diff.Unit * i
		root.Velocity,root.RotVelocity=Vector3.new(),Vector3.new()
		workspace.CurrentCamera.CFrame=workspace.CurrentCamera.CFrame+Vector3.new(0,9,0)
		game:GetService("RunService").RenderStepped:Wait()
	end
	--j:Destroy()
	noclipppp=false
	root.CFrame = cf
	dance:Stop()
	workspace.Gravity = oldg
end
local function smoothTP(cf)
	if (cf.p-root.Position).Magnitude > 95 then
		local btns = workspace.JobButtons:GetChildren()
		if player:FindFirstChild("House") and player.House.Value then
			btns[#btns+1] = player.House.Value:FindFirstChild("Marker") 
		end
		table.sort(btns,function(a,b) return (a.Position-cf.p).Magnitude < (b.Position-cf.p).Magnitude end)
		if (btns[1].Position-cf.p).Magnitude < (cf.p-root.Position).Magnitude then
			game:GetService("ReplicatedStorage").PlayerChannel:FireServer("TeleportToJob", ((btns[1].Name == "Marker") and "House" or btns[1].Name))
			wait(0.7)
			if (cf.p-root.Position).Magnitude < 8 then
				return
			end
		end
	end
	smoothTP2(cf)
end
for _,o in ipairs(workspace.Ovens:GetChildren()) do
	if ffc(o,"Bottom") then
		o.Bottom.CanTouch = false
	end
end
local function tryCook()
	for zz=1,18 do
		local order = getOrders()[1]
		local topping
		if order=="Pepperoni" or order=="Sausage" then topping=order end
		local cookD = FindFirstDew()
		local badD = FindBadDew()
		local raw,cookP,trash
		if topping then
			--pepperoni order avoids sausage dough and vice verca
			raw,cookP,trash = FindDoughAndWithout(topping=="Pepperoni" and "Sausage" or "Pepperoni")
		else
			raw,cookP,trash = FindDoughAndWithout()
		end
		local ovens = workspace.Ovens:GetChildren()
		for i=#ovens,1,-1 do
			if #ovens[i]:GetChildren() < 10 then
				table.remove(ovens,i)
			end
		end
		for i = #ovens, 2, -1 do --shuffle
			local j = RNG:NextInteger(1, i)
			ovens[j], ovens[i] = ovens[i], ovens[j]
		end
		if doCook then
			local didsomething=false
			--move final pizza
			if cookP and tick()-cookPtick>0.8 then
				local oven = getOvenNear(cookP.Position)
				if oven==nil or oven.IsOpen.Value then
					cookPtick=tick()
					didsomething=true
					if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
					network:FireServer("UpdateProperty", cookP, "CFrame", CFrame.new(RNG:NextNumber(56,57),4.1,38))
				end
			end
			if order then
				if order=="Dew" and cookD and tick()-cookDtick>0.8 then
					--move dew if ordered
					cookDtick=tick()
					didsomething=true
					if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
					network:FireServer("UpdateProperty", cookD, "CFrame", CFrame.new(53,4.68,36.5))
				elseif order~="Dew" and raw and raw.Parent and supplyCounts[order]>0 and supplyCounts.TomatoSauce>0 and supplyCounts.Cheese>0 then
					--make pizza
					if raw.Mesh.Scale.Y>1.5 then
						if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
						didsomething=true
						network:FireServer("UpdateProperty", raw, "CFrame", CFrame.new(RNG:NextNumber(29.6,44.6),3.7,RNG:NextNumber(42.5,48.5)))
						wait()
						network:FireServer("SquishDough", raw)
					else
						--make sure it will have an oven
						local oven
						for _,o in ipairs(ovens) do
							if isFullyOpen(o) then
								local other = getDoughNear(o.Bottom.Position)
								if other==nil or not (other.BrickColor.Name=="Bright orange" and ffc(other.SG.Frame,"TomatoSauce") and ffc(other.SG.Frame,"MeltedCheese")) then
									if other then
										--replace mistaken dough
										didsomething=true
										if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
										network:FireServer("UpdateProperty", other, "CFrame", CFrame.new(RNG:NextNumber(29.6,44.6),3.7,RNG:NextNumber(42.5,48.5)))
										wait()
									end
									oven=o
									break
								end
							end
						end
						if oven and raw.Parent==workspace.AllDough then
							--make
							if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
							didsomething=true
							network:FireServer("AddIngredientToPizza", raw,"TomatoSauce")
							network:FireServer("AddIngredientToPizza", raw,"Cheese")
							network:FireServer("AddIngredientToPizza", raw,topping)
							network:FireServer("UpdateProperty", raw, "CFrame", oven.Bottom.CFrame+Vector3.new(0,0.7,0))
							oven.Door.ClickDetector.Detector:FireServer()
							--mark as cooking
							cookingDict[order]=cookingDict[order]+1
							local revoked=false
							spawn(function()
								raw.AncestryChanged:Wait()
								if not revoked then
									cookingDict[order]=cookingDict[order]-1
									revoked=true
								end
							end)
							delay(40, function()
								if not revoked then
									cookingDict[order]=cookingDict[order]-1
									revoked=true
								end
							end)
						end
					end
				end
			end
			--open unnecessarily closed ovens
			for _,o in ipairs(ovens) do
				local bar = o.Door.Meter.SurfaceGui.ProgressBar.Bar
				if o.IsOpen.Value==false and (o.IsCooking.Value==false or (Vector3.new(bar.ImageColor3.r,bar.ImageColor3.g,bar.ImageColor3.b)-Vector3.new(.871,.518,.224)).magnitude>.1) then
					didsomething=true
					if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
					o.Door.ClickDetector.Detector:FireServer()
					break
				end
			end
			--trash
			if badD then
				didsomething=true
				if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
				network:FireServer("UpdateProperty", badD, "CFrame", CFrame.new(RNG:NextNumber(28,30), 1.7, RNG:NextNumber(55,57)))
			end
			if trash and (trash.IsBurned.Value==false or getOvenNear(trash.Position)==nil or getOvenNear(trash.Position).IsOpen.Value) then
				--closed oven breaks if you take burnt out of it
				didsomething=true
				if (root.Position-Vector3.new(36.64, 3.80, 54.11)).magnitude>9 then  smoothTP(CFrame.new(36.64, 3.80, 54.11)) wait(.1) end
				network:FireServer("UpdateProperty", trash, "CFrame", CFrame.new(47.90, 7.00, 72.49, 1, 0, -0, 0, 0, 1, 0, -1, 0))
			end
			if didsomething then wait(0.5) else break end
		else
			break
		end
	end
end
wait(1)
--//main loop
while gui.Parent do
	wait(0.9)
	humanoid.Sit=false
	if RNG:NextInteger(1,20)==1 then
		game:GetService("VirtualInputManager"):SendKeyEvent(true,"Z",false,game)
		wait()
		game:GetService("VirtualInputManager"):SendKeyEvent(false,"Z",false,game)
	end
	for zz=1,3 do
		local c,order = FindFirstCustomer()
		if doCashier and c and order then
			local reg = 3
			if c.Head.Position.X < 50 then
				reg = 2
			elseif c.Head.Position.X < 70 then
				reg = 1
			end
			if (root.Position-Vector3.new(50.30, 3.80, 83.24)).magnitude>9 then smoothTP(CFrame.new(50.30, 3.80, 83.24)) wait(.1) end
			network:FireServer("OrderComplete", c, order, workspace["Register"..reg])
			wait(0.3)
		else
			break
		end
	end
	tryCook()
	for zz=1,7 do
		if doBoxer then
			local didsomething = false
			local boxP,boxD = FindBoxingFoods()
			local closedBox,openBox,fullBox = FindBoxes()
			if boxD and tick()-boxDtick>0.8 then
				boxDtick=tick()
				didsomething=true
				if (root.Position-Vector3.new(58.74, 3.80, 12.400)).magnitude>9 then  smoothTP(CFrame.new(58.74, 3.80, 12.40))wait(.1) continue end
				network:FireServer("UpdateProperty", boxD, "CFrame", CFrame.new(63,4.9,-1,-1,0,0,0,1,0,0,0,-1))
			end
			if fullBox then
				if fullBox.Name=="BoxOpen" then
					didsomething=true
					if (root.Position-Vector3.new(58.74, 3.80, 12.400)).magnitude>9 then  smoothTP(CFrame.new(58.74, 3.80, 12.40))wait(.1) continue end
					network:FireServer("CloseBox", fullBox)
					--will be moved next loop
				elseif tick()-boxPtick>0.8 then
					didsomething=true
					if (root.Position-Vector3.new(58.74, 3.80, 12.400)).magnitude>9 then  smoothTP(CFrame.new(58.74, 3.80, 12.40))wait(.1) continue end
					network:FireServer("UpdateProperty", fullBox, "CFrame", CFrame.new(68.2,4.4,RNG:NextNumber(-3,-2),-1,0,0,0,1,0,0,0,-1))
					boxPtick=tick()
				end
			end
			if closedBox and not openBox then
				didsomething=true
				if (root.Position-Vector3.new(58.74, 3.80, 12.400)).magnitude>9 then  smoothTP(CFrame.new(58.74, 3.80, 12.40))wait(.1) continue end
				network:FireServer("UpdateProperty", closedBox, "CFrame", CFrame.new(RNG:NextNumber(62.5,70.5),3.5,RNG:NextNumber(11,25)))
				wait()
				network:FireServer("OpenBox", closedBox)
			end
			if openBox and boxP then
				didsomething=true
				if (root.Position-Vector3.new(58.74, 3.80, 12.400)).magnitude>9 then  smoothTP(CFrame.new(58.74, 3.80, 12.40))wait(.1) continue end
				network:FireServer("UpdateProperty", boxP, "Anchored", true)
				network:FireServer("UpdateProperty", openBox, "Anchored", true)
				wait()
				network:FireServer("UpdateProperty", boxP, "CFrame", openBox.CFrame+Vector3.new(0,-2,0))
				wait()
				network:FireServer("AssignPizzaToBox", openBox, boxP)
			end
			if didsomething then wait(0.5) else break end
		else
			break
		end
	end
	if doDelivery then
		local wstools = FindAllDeliveryTools(workspace)
		if #wstools > 1 or (wstools[1] and ffc(wstools[1].Handle,"X10")) then
			--get tools
			if (root.Position-Vector3.new(54.45, 4.02, -15)).magnitude>9 then smoothTP(CFrame.new(54.45, 4.02, -15)) wait(.1) end
			for i=1,#wstools do
				if wstools[i].Parent == workspace then
					humanoid:EquipTool(wstools[i])
					wait()
				end
			end
			wait(0.3)
			local t = FindAllDeliveryTools(character)
			for i=1,#t do
				t[i].Parent = player.Backpack
			end
			wait(0.1)
			if ffc(character,"RightHand") and ffc(character.RightHand,"RightGrip") then
				character.RightHand.RightGrip:Destroy()
			end
		end
		local bptools = FindAllDeliveryTools(player.Backpack)
		if #bptools >= settings.deliver_at and #bptools > 0 and tick()-delTick > 30 then
			--deliver to houses
			table.sort(bptools,function(a,b)
				a,b=tostring(a),tostring(b)
				if (a:sub(1,1)=="B" and b:sub(1,1)=="B") then
					return a < b
				end
				return a > b
			end)
			local fatass=false
			for i=1,#bptools do
				if not doDelivery then
					break
				end
				humanoid.Sit=false
				local tool = bptools[i]
				local giver = getHousePart(tool.Name)
				local ogp = giver.Position
				if giver then
					if (giver.Position-root.Position).Magnitude > 9 then
						smoothTP(giver.CFrame+Vector3.new(0,7,0))
						if giver.Parent==nil or (giver.Position-ogp).Magnitude>1 then
							giver = getHousePart(tool.Name) or giver
							smoothTP(giver.CFrame+Vector3.new(0,7,0))
						end
						pcall(function() tool.Parent = character end)
						wait(1.2)
						local t = FindAllDeliveryTools(character)
						for i=1,#t do
							if t[i] ~= tool then
								t[i].Parent = player.Backpack
							end
						end
						wait(2)
						fatass=false
					else
						if fatass then
							wait(0.2)
						else
							wait(0.7)
						end
						pcall(function() tool.Parent = character end)
						wait()
						fatass=true
					end
				end
			end
			delTick = tick()
		end
	end
	tryCook()
	if doSupplier then
		local refill=false
		for s,c in pairs(supplyCounts) do
			if c <= settings.refill_at then
				refill=true
				break
			end
		end
		if refill then
			local oldcf = root.CFrame
			local waiting = false
			local waitingTick = 0
			local lastBox
			while doSupplier do
				--check if refill is done otherwise hit buttons
				local fulfilled=true
				local boxes = workspace.AllSupplyBoxes:GetChildren()
				for yy=1,2 do
					local needtp=true
					local realc = 0
					for _,btn in ipairs(supplyButtons) do
						local s = bcolorToSupply[btn.BrickColor.Name]
						if supplyCounts[s] < settings.refill_end then
							local count = 0
							if #boxes > 30 then
								for i=1,#boxes do
									local box = boxes[i]
									if bcolorToSupply[box.BrickColor.Name]==s and box.Anchored==false and box.Position.Z < -940 then
										count=count+1
									end
								end
							end
							if count < 2 then
								if needtp then
									needtp=false
									smoothTP(btn.CFrame + Vector3.new(0,3,2.5))
									wait(0.1)
								end
								if not doSupplier then break end
								root.CFrame = btn.CFrame + Vector3.new(0,3,0)
								wait(0.1)
								realc=realc+1
							end
							fulfilled=false
						end
					end
					wait(0.2)
					if yy == 1 and realc < 3 then
						wait(0.6)
					end
				end
				if fulfilled or not (doSupplier) then
					break
				end
				smoothTP(CFrame.new(8,12.4,-1020))
				if not doSupplier then break end
				--check if can finish waiting for boxes to move
				if waiting and (lastBox.Position.X>42 or tick()-waitingTick>6) then
					waiting=false
					if lastBox.Position.X<42 then
						--clear boxes if stuck
						smoothTP(CFrame.new(20.5,8,-35))
						wait(0.1)
						local boxes = workspace.AllSupplyBoxes:GetChildren()
						for i=1,#boxes do
							local box = boxes[i]
							if box.Anchored==false and box.Position.Z>-55 then
								network:FireServer("UpdateProperty", box, "CFrame", CFrame.new(RNG:NextNumber(0,40),RNG:NextNumber(-10,-30),-70))
								wait()
							end
						end
						wait(0.1)
					end
				end
				if not waiting then
					--move boxes
					if root.Position.Z > -900 then smoothTP(CFrame.new(8,12.4,-1020)) end
					wait(0.1)
					lastBox=nil
					local j=0
					local boxes = workspace.AllSupplyBoxes:GetChildren()
					for i=1,#boxes do
						local box = boxes[i]
						if box.Anchored==false and box.Position.Z < -940 and bcolorToSupply[box.BrickColor.Name] and supplyCounts[bcolorToSupply[box.BrickColor.Name]]<settings.refill_end then
							box.CFrame = CFrame.new(38-4.3*math.floor(j/2),5,-7-5*(j%2))
							network:FireServer("UpdateProperty", box, "CFrame", box.CFrame)
							lastBox=box
							j=j+1
							if j>13 then break end
						end
					end
					if lastBox then
						waiting=true
						waitingTick=tick()
					end
				end
			end
			--smoothTP(oldcf)
		end
	end
end
INFO