
KeylessUniversal

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local moveDirection = Vector3.new(math.random() * 2 - 1, 0, math.random() * 2 - 1).Unit
local isStanding = false
local standStart = 0
local standDuration = 0
local walkDuration = 0
local walkUntil = 0
local checkCooldown = 0
local centerPosition = nil
local wanderRadius = 0
local lastPositions = {}
local stuckDetected = false
local stuckCounter = 0
local maxStuckTime = 3
local obstacleMemory = {}
local lastObstacleTime = 0
local obstacleMemoryDuration = 5
local emotionalState = "neutral"
local emotionalStateTimer = math.random(50, 150) / 10
local emotionalStateDuration = math.random(50, 150) / 10
local curiosityLevel = 0.5
local socialAwareness = 0.5
local personalityTraits = {}
local frameCount = 0
local lastFrameUpdate = 0
local utilityScores = {}
local nearbyPlayers = {}
local playerDetectionRange = 15
local personalSpace = 4
local imitationChance = 0.3
local curiosityTarget = nil
local curiosityTimer = 0
local boredomLevel = 0.3
local npcEnabled = true
personalityTraits = {
patience = 0.7 + math.random() * 0.25,
sociability = 0.2 + math.random() * 0.5,
curiosity = 0.3 + math.random() * 0.5,
caution = 0.4 + math.random() * 0.5,
energy = 0.5 + math.random() * 0.4,
consistency = 0.6 + math.random() * 0.35,
playfulness = 0.3 + math.random() * 0.5,
anxiety = 0.1 + math.random() * 0.4,
focus = 0.5 + math.random() * 0.4,
adaptability = 0.4 + math.random() * 0.5
}
local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Name = "NPCControl"
ScreenGui.ResetOnSpawn = false
ScreenGui.IgnoreGuiInset = true
pcall(function()
if player.PlayerGui:FindFirstChild("NPCControl") then
player.PlayerGui:FindFirstChild("NPCControl"):Destroy()
end
end)
ScreenGui.Parent = player.PlayerGui
local function createBorder(parent, zIndex)
local left = Instance.new("Frame")
left.Size = UDim2.new(0, 1, 1, 0)
left.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
left.BorderSizePixel = 0
left.ZIndex = zIndex
left.Active = false
left.Parent = parent
local top = Instance.new("Frame")
top.Size = UDim2.new(1, 0, 0, 1)
top.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
top.BorderSizePixel = 0
top.ZIndex = zIndex
top.Active = false
top.Parent = parent
local right = Instance.new("Frame")
right.Size = UDim2.new(0, 1, 1, 0)
right.Position = UDim2.new(1, -1, 0, 0)
right.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
right.BorderSizePixel = 0
right.ZIndex = zIndex
right.Active = false
right.Parent = parent
local bottom = Instance.new("Frame")
bottom.Size = UDim2.new(1, 0, 0, 1)
bottom.Position = UDim2.new(0, 0, 1, -1)
bottom.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
bottom.BorderSizePixel = 0
bottom.ZIndex = zIndex
bottom.Active = false
bottom.Parent = parent
end
local mainFrame = Instance.new("Frame")
mainFrame.Size = UDim2.new(0, 240, 0, 50)
mainFrame.Position = UDim2.new(0.5, -120, 0, 50)
mainFrame.BackgroundColor3 = Color3.fromRGB(12, 12, 12)
mainFrame.BorderSizePixel = 0
mainFrame.ZIndex = 100
mainFrame.ClipsDescendants = true
mainFrame.Parent = ScreenGui
createBorder(mainFrame, 200)
local titleBar = Instance.new("Frame")
titleBar.Size = UDim2.new(1, -2, 0, 22)
titleBar.Position = UDim2.new(0, 1, 0, 1)
titleBar.BackgroundColor3 = Color3.fromRGB(12, 12, 12)
titleBar.BorderSizePixel = 0
titleBar.ZIndex = 101
titleBar.Parent = mainFrame
local titleLabel = Instance.new("TextLabel")
titleLabel.Size = UDim2.new(1, -30, 1, 0)
titleLabel.Position = UDim2.new(0, 8, 0, 0)
titleLabel.BackgroundTransparency = 1
titleLabel.Text = "NPC | Control"
titleLabel.TextColor3 = Color3.fromRGB(180, 180, 180)
titleLabel.Font = Enum.Font.Code
titleLabel.TextSize = 12
titleLabel.TextXAlignment = Enum.TextXAlignment.Left
titleLabel.ZIndex = 102
titleLabel.Parent = titleBar
local collapseButton = Instance.new("TextButton")
collapseButton.Size = UDim2.new(0, 22, 0, 22)
collapseButton.Position = UDim2.new(1, -22, 0, 0)
collapseButton.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
collapseButton.BorderSizePixel = 0
collapseButton.Text = "-"
collapseButton.TextColor3 = Color3.fromRGB(200, 200, 200)
collapseButton.Font = Enum.Font.Code
collapseButton.TextSize = 14
collapseButton.ZIndex = 102
collapseButton.Parent = titleBar
createBorder(collapseButton, 103)
local titleDivider = Instance.new("Frame")
titleDivider.Size = UDim2.new(1, -2, 0, 1)
titleDivider.Position = UDim2.new(0, 1, 0, 23)
titleDivider.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
titleDivider.BorderSizePixel = 0
titleDivider.ZIndex = 200
titleDivider.Parent = mainFrame
local contentFrame = Instance.new("Frame")
contentFrame.Size = UDim2.new(1, -2, 1, -25)
contentFrame.Position = UDim2.new(0, 1, 0, 24)
contentFrame.BackgroundTransparency = 1
contentFrame.ZIndex = 101
contentFrame.Parent = mainFrame
local isDragging = false
local dragStart = nil
local frameStartPos = nil
local function startDrag(input)
isDragging = true
dragStart = input.Position
frameStartPos = mainFrame.Position
end
local function stopDrag()
isDragging = false
end
titleBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
startDrag(input)
end
end)
titleBar.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
stopDrag()
end
end)
titleLabel.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
startDrag(input)
end
end)
titleLabel.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
stopDrag()
end
end)
UserInputService.InputChanged:Connect(function(input)
if isDragging and (input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement) then
local delta = input.Position - dragStart
mainFrame.Position = UDim2.new(
frameStartPos.X.Scale,
frameStartPos.X.Offset + delta.X,
frameStartPos.Y.Scale,
frameStartPos.Y.Offset + delta.Y
)
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
stopDrag()
end
end)
collapseButton.MouseButton1Click:Connect(function()
if mainFrame.Size.Y.Offset > 24 then
mainFrame:TweenSize(UDim2.new(0, 240, 0, 24), "Out", "Quad", 0.2, true)
collapseButton.Text = "+"
contentFrame.Visible = false
else
mainFrame:TweenSize(UDim2.new(0, 240, 0, 50), "Out", "Quad", 0.2, true)
collapseButton.Text = "-"
contentFrame.Visible = true
end
end)
local function createToggle(toggleText, yPosition, default, callback)
local button = Instance.new("TextButton")
button.Size = UDim2.new(0, 210, 0, 22)
button.Position = UDim2.new(0.5, -105, 0, yPosition)
button.BackgroundColor3 = default and Color3.fromRGB(25, 45, 25) or Color3.fromRGB(30, 30, 30)
button.Text = toggleText .. ": " .. (default and "ON" or "OFF")
button.TextColor3 = Color3.fromRGB(200, 200, 200)
button.Font = Enum.Font.Code
button.TextSize = 11
button.BorderSizePixel = 0
button.ZIndex = 150
button.Active = true
button.Selectable = true
button.Parent = contentFrame
createBorder(button, 149)
local state = default
local debounce = false
local function toggle()
if debounce then return end
debounce = true
state = not state
button.Text = toggleText .. ": " .. (state and "ON" or "OFF")
button.BackgroundColor3 = state and Color3.fromRGB(25, 45, 25) or Color3.fromRGB(30, 30, 30)
callback(state)
task.delay(0.3, function()
debounce = false
end)
end
button.Activated:Connect(toggle)
return button
end
createToggle("NPC MODE", 2, true, function(state)
npcEnabled = state
if not npcEnabled and humanoid then
humanoid:MoveTo(rootPart.Position)
end
end)
local function isValidCharacter()
if not character or not character.Parent then return false end
if not humanoid or not humanoid.Parent then return false end
if not rootPart or not rootPart.Parent then return false end
if humanoid.Health <= 0 then return false end
return true
end
local function findMapCenter()
local parts = {}
local children = Workspace:GetChildren()
for _, child in ipairs(children) do
if child:IsA("BasePart") and child.CanCollide and child.Transparency < 0.5 and child.Size.Magnitude > 3 then
table.insert(parts, child)
end
if child:IsA("Model") then
for _, descendant in ipairs(child:GetDescendants()) do
if descendant:IsA("BasePart") and descendant.CanCollide and descendant.Transparency < 0.5 and descendant.Size.Magnitude > 3 then
table.insert(parts, descendant)
end
end
end
end
if #parts == 0 then
return rootPart.Position, 20
end
local minX, maxX = math.huge, -math.huge
local minZ, maxZ = math.huge, -math.huge
for _, part in ipairs(parts) do
local pos = part.Position
local size = part.Size
minX = math.min(minX, pos.X - size.X / 2)
maxX = math.max(maxX, pos.X + size.X / 2)
minZ = math.min(minZ, pos.Z - size.Z / 2)
maxZ = math.max(maxZ, pos.Z + size.Z / 2)
end
local center = Vector3.new((minX + maxX) / 2, rootPart.Position.Y, (minZ + maxZ) / 2)
local radius = math.min((maxX - minX) / 2, (maxZ - minZ) / 2) * 0.6
return center, math.max(radius, 10)
end
local function getRandomDirection()
local angle = math.random() * math.pi * 2
return Vector3.new(math.cos(angle), 0, math.sin(angle))
end
local function isBlocked(direction, distance)
if not isValidCharacter() then return false end
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {character}
local rayOrigin = rootPart.Position + Vector3.new(0, 1, 0)
local rayResult = Workspace:Raycast(rayOrigin, direction * distance, rayParams)
if not rayResult then return false end
local hit = rayResult.Instance
if hit and hit.CanCollide and hit.Transparency < 0.5 and hit.Size.Magnitude > 0.5 then
return true
end
if hit and hit.Parent then
local hitPlayer = Players:GetPlayerFromCharacter(hit.Parent)
if hitPlayer then return true end
end
return false
end
local function isEdgeAhead(direction, distance)
if not isValidCharacter() then return false end
local checkPosition = rootPart.Position + direction * distance + Vector3.new(0, 0.5, 0)
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {character}
local rayOrigin = checkPosition + Vector3.new(0, 3, 0)
local rayResult = Workspace:Raycast(rayOrigin, Vector3.new(0, -15, 0), rayParams)
if not rayResult then return true end
local hitPart = rayResult.Instance
if hitPart and (not hitPart.CanCollide or hitPart.Transparency >= 0.5) then return true end
local heightDiff = math.abs(rootPart.Position.Y - rayResult.Position.Y)
if heightDiff > 4 then return true end
return false
end
local function getDirectionAwayFromBarrier()
if not isValidCharacter() then return -moveDirection end
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
rayParams.FilterDescendantsInstances = {character}
local bestDir = nil
local bestDist = 0
for i = 1, 36 do
local angle = math.random() * math.pi * 2
local dir = Vector3.new(math.cos(angle), 0, math.sin(angle))
local rayOrigin = rootPart.Position + Vector3.new(0, 1, 0)
local rayResult = Workspace:Raycast(rayOrigin, dir * 10, rayParams)
local dist = rayResult and (rayResult.Position - rayOrigin).Magnitude or 10
if dist > bestDist and not isEdgeAhead(dir, 5) then
bestDist = dist
bestDir = dir
end
end
if bestDir then return bestDir end
local perpDir = moveDirection:Cross(Vector3.new(0, 1, 0))
if math.random() < 0.5 then perpDir = -perpDir end
local newDir = (-moveDirection + perpDir).Unit
if isEdgeAhead(newDir, 5) or isBlocked(newDir, 3) then
newDir = -moveDirection
end
return newDir
end
local function getWanderDirection()
if not centerPosition then
centerPosition, wanderRadius = findMapCenter()
end
if not isValidCharacter() then return getRandomDirection() end
local toCenter = centerPosition - rootPart.Position
toCenter = Vector3.new(toCenter.X, 0, toCenter.Z)
local distToCenter = toCenter.Magnitude
if distToCenter > wanderRadius then
return toCenter.Unit
else
local baseAngle = math.atan2(toCenter.Z, toCenter.X)
local angleVariation = math.random() * math.pi / 3 - math.pi / 6
local directionChoice = math.random()
local newAngle
if directionChoice < 0.33 then
newAngle = baseAngle + math.pi / 2 + angleVariation
elseif directionChoice < 0.66 then
newAngle = baseAngle - math.pi / 2 + angleVariation
else
newAngle = baseAngle + angleVariation
end
local newDir = Vector3.new(math.cos(newAngle), 0, math.sin(newAngle))
if isEdgeAhead(newDir, 5) then
newDir = getDirectionAwayFromBarrier()
end
return newDir
end
end
local function checkStuck()
if not isValidCharacter() then return end
table.insert(lastPositions, rootPart.Position)
if #lastPositions > 30 then table.remove(lastPositions, 1) end
if #lastPositions >= 30 then
local totalMovement = 0
for i = 2, #lastPositions do
totalMovement = totalMovement + (lastPositions[i] - lastPositions[i-1]).Magnitude
end
if totalMovement < 0.5 then
stuckCounter = stuckCounter + 0.1
if stuckCounter >= maxStuckTime then
stuckDetected = true
stuckCounter = 0
end
else
stuckCounter = math.max(0, stuckCounter - 0.2)
stuckDetected = false
end
end
end
local function updateNearbyPlayers()
nearbyPlayers = {}
if not isValidCharacter() then return end
for _, plr in ipairs(Players:GetPlayers()) do
if plr ~= player then
local char = plr.Character
if char then
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp then
local dist = (rootPart.Position - hrp.Position).Magnitude
if dist < playerDetectionRange then
table.insert(nearbyPlayers, {player = plr, distance = dist, position = hrp.Position})
end
end
end
end
end
end
local function updateBehaviorTree()
utilityScores = {}
if not isValidCharacter() then
utilityScores.idleStand = 10
return "idleStand"
end
utilityScores.avoidEdge = (isEdgeAhead(moveDirection, 4) and not isStanding) and 11 or 0
utilityScores.avoidObstacle = (isBlocked(moveDirection, 4) and not isStanding) and 10 or 0
utilityScores.escapeStuck = stuckDetected and 9 or 0
utilityScores.returnToCenter = (centerPosition and (centerPosition - rootPart.Position).Magnitude > wanderRadius) and 8 or 0
utilityScores.wanderRandomly = (not isStanding and not stuckDetected) and 5 or 0
utilityScores.idleStand = isStanding and 3 or 0
utilityScores.explore = (emotionalState == "curious" or emotionalState == "energetic" or emotionalState == "playful") and 6 or 0
utilityScores.socialInteraction = (socialAwareness > 0.5 and #nearbyPlayers > 0) and 4 or 0
utilityScores.imitate = (math.random() < imitationChance and #nearbyPlayers > 0) and 2 or 0
utilityScores.curious = (curiosityLevel > 0.7) and 7 or 0
local highestUtility = 0
local bestBehavior = "idleStand"
for behavior, utility in pairs(utilityScores) do
if utility > highestUtility then
highestUtility = utility
bestBehavior = behavior
end
end
return bestBehavior
end
local function executeBehavior(behavior)
if not isValidCharacter() then return end
if behavior == "avoidEdge" then
moveDirection = getDirectionAwayFromBarrier()
isStanding = true
standStart = tick()
standDuration = 2
elseif behavior == "avoidObstacle" then
moveDirection = getDirectionAwayFromBarrier()
if math.random() < personalityTraits.caution then
isStanding = true
standStart = tick()
standDuration = 2
end
elseif behavior == "escapeStuck" then
moveDirection = getDirectionAwayFromBarrier()
isStanding = false
walkDuration = math.random(20, 35) / 10
walkUntil = tick() + walkDuration
stuckDetected = false
lastPositions = {}
elseif behavior == "returnToCenter" then
local toCenter = (centerPosition - rootPart.Position).Unit
moveDirection = toCenter
isStanding = false
walkDuration = math.random(30, 50) / 10
walkUntil = tick() + walkDuration
elseif behavior == "wanderRandomly" then
if not isStanding then
local targetPos = rootPart.Position + moveDirection * 10
humanoid:MoveTo(targetPos)
end
elseif behavior == "idleStand" then
humanoid:MoveTo(rootPart.Position)
elseif behavior == "explore" then
if not isStanding then
local targetPos = rootPart.Position + moveDirection * 15
humanoid:MoveTo(targetPos)
end
elseif behavior == "socialInteraction" then
if #nearbyPlayers > 0 then
local target = nearbyPlayers[1]
local dirToPlayer = (target.position - rootPart.Position).Unit
if target.distance < personalSpace then
moveDirection = getDirectionAwayFromBarrier()
else
moveDirection = dirToPlayer
end
end
elseif behavior == "imitate" then
if #nearbyPlayers > 0 and math.random() < 0.3 then
local target = nearbyPlayers[math.random(1, #nearbyPlayers)]
local targetChar = target.player.Character
if targetChar then
local targetHRP = targetChar:FindFirstChild("HumanoidRootPart")
if targetHRP then
local targetVelocity = targetHRP.Velocity
if targetVelocity.Magnitude > 1 then
moveDirection = targetVelocity.Unit
end
end
end
end
elseif behavior == "curious" then
if not curiosityTarget then
local randomAngle = math.random() * math.pi * 2
local randomDist = math.random(10, 30)
curiosityTarget = rootPart.Position + Vector3.new(math.cos(randomAngle), 0, math.sin(randomAngle)) * randomDist
curiosityTimer = math.random(30, 80) / 10
end
if curiosityTarget then
moveDirection = (curiosityTarget - rootPart.Position).Unit
curiosityTimer = curiosityTimer - 0.1
if curiosityTimer <= 0 then
curiosityTarget = nil
end
end
end
end
local function onHeartbeat()
if not isValidCharacter() then
if player.Character and player.Character ~= character then
character = player.Character
humanoid = character:WaitForChild("Humanoid")
rootPart = character:WaitForChild("HumanoidRootPart")
centerPosition, wanderRadius = findMapCenter()
moveDirection = getWanderDirection()
isStanding = false
walkDuration = math.random(25, 50) / 10
walkUntil = tick() + walkDuration
checkCooldown = 0
lastPositions = {}
stuckDetected = false
stuckCounter = 0
obstacleMemory = {}
end
return
end
if not npcEnabled then return end
local now = tick()
if now - lastFrameUpdate < 0.05 then return end
lastFrameUpdate = now
checkStuck()
updateNearbyPlayers()
local bestBehavior = updateBehaviorTree()
executeBehavior(bestBehavior)
if checkCooldown > now then return end
if isStanding then
humanoid:MoveTo(rootPart.Position)
if now - standStart >= standDuration then
isStanding = false
moveDirection = getWanderDirection()
walkDuration = math.random(25, 50) / 10
walkUntil = now + walkDuration
end
return
end
if isEdgeAhead(moveDirection, 4) then
moveDirection = getDirectionAwayFromBarrier()
isStanding = true
standStart = now
standDuration = 2
checkCooldown = now + 0.3
return
end
if isBlocked(moveDirection, 4) then
moveDirection = getDirectionAwayFromBarrier()
isStanding = true
standStart = now
standDuration = 2
checkCooldown = now + 0.3
return
end
humanoid:MoveTo(rootPart.Position + moveDirection * 10)
if now >= walkUntil then
isStanding = true
standStart = now
standDuration = math.random(15, 30) / 10
end
end
centerPosition, wanderRadius = findMapCenter()
moveDirection = getWanderDirection()
walkDuration = math.random(25, 50) / 10
walkUntil = tick() + walkDuration
RunService.Heartbeat:Connect(onHeartbeat)
player.CharacterAdded:Connect(function(newCharacter)
character = newCharacter
humanoid = character:WaitForChild("Humanoid")
rootPart = character:WaitForChild("HumanoidRootPart")
centerPosition, wanderRadius = findMapCenter()
moveDirection = getWanderDirection()
isStanding = false
walkDuration = math.random(25, 50) / 10
walkUntil = tick() + walkDuration
checkCooldown = 0
lastPositions = {}
stuckDetected = false
stuckCounter = 0
obstacleMemory = {}
end)



i may be confused but this script makes you just act like an npc?