--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