-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] run_on_thread(getactorthreads()[1], [[ getrenv()._G.globals.fpv_sol_spread={spread=0} local Players, Workspace = game:GetService'Players', workspace local CurrentCamera = Workspace.CurrentCamera local GlobalEnvironment = getrenv()._G local GlobalVariables, ExecutionMap = GlobalEnvironment.globals, (getupvalues or debug and debug.getupvalues)(GlobalEnvironment.append_exe_set)[1] local ClientState, SoldierTeams, SoldiersSpawned, SoldiersAlive, SoldierModels = GlobalVariables.cli_state, GlobalVariables.sol_teams, GlobalVariables.soldiers_spawned, GlobalVariables.soldiers_alive, GlobalVariables.soldier_models local function GetClosestPlayer() local ClosestPlayer, ClosestDistance, FirstPersonViewID = nil, math.huge, ClientState.fpv_sol_id local MyTeam = SoldierTeams[FirstPersonViewID] for PlayerID, IsSpawned in SoldiersSpawned do if IsSpawned and SoldiersAlive[PlayerID] and PlayerID ~= FirstPersonViewID and SoldierTeams[PlayerID] ~= MyTeam then local Character = SoldierModels[PlayerID] if Character and Character.PrimaryPart then local Head = Character:FindFirstChild'Head' or Character.PrimaryPart local Distance = (Head.Position - CurrentCamera.CFrame.Position).Magnitude if Distance < ClosestDistance then ClosestDistance = Distance ClosestPlayer = Head end end end end return ClosestPlayer end local OriginalSpawnFunction = ExecutionMap[GlobalEnvironment.exe_func_t.SPAWN_FPV_SOL_BULLET] ExecutionMap[GlobalEnvironment.exe_func_t.SPAWN_FPV_SOL_BULLET] = function(BulletID, BulletType, SpawnPosition, Velocity) local Target = GetClosestPlayer() if Target then Velocity = (Target.Position - SpawnPosition).Unit * Velocity.Magnitude end return OriginalSpawnFunction(BulletID, BulletType, SpawnPosition, Velocity) end local ESP = { Config = { ZIndex = 2, Enabled = true, ShowHealthBars = true, ShowNames = true, ShowBoxes = true, ShowDistance = true, ShowTools = true, BoxThickness = 1, NameFont = 1, FontSize = 12, NameColor = Color3.new(1, 1, 1), BoxColor = Color3.new(1, 1, 1), HealthBarWidth = 2, HealthBarHeight = 10, MaxDistance = 100, ToolIconSize = 16 }, Callbacks = { getPartsToRenderCallback = nil, partToHealthCallback = nil, partToToolsToRenderCallback = nil }, _activeObjects = {}, _drawingObjects = {}, _cache = { parts = {}, health = {}, tools = {}, lastUpdate = 0, updateInterval = 0.1 }, _connections = {} } if DrawingImmediate then function ESP:WorldToScreen(worldPosition) local camera = workspace.CurrentCamera; if not camera then return nil end; local vector, onScreen = camera:WorldToViewportPoint(worldPosition) if onScreen and vector.Z > 0 then return Vector2.new(vector.X, vector.Y), vector.Z end; return nil, nil end; function ESP:GetHealthColor(currentHealth, maxHealth) if not currentHealth or not maxHealth or maxHealth <= 0 then return Color3.new(1, 1, 1) end; local percent = currentHealth / maxHealth; if percent > 0.7 then return Color3.new(0, 1, 0) elseif percent > 0.3 then return Color3.new(1, 1, 0) else return Color3.new(1, 0, 0) end end; function ESP:GetPartBoxSize(part) if not part then return 2, 2 end; if part:IsA("Model") then local size = part:GetExtentsSize() return size.X * 2, size.Y * 2 end; if part:IsA("BasePart") then local size = part.Size; return size.X, size.Y end; return 2, 2 end; function ESP:GetPartPosition(part) if part:IsA("Model") then local primary = part.PrimaryPart; if primary then return primary.Position end; local total = Vector3.new(0, 0, 0) local count = 0; for _, child in ipairs(part:GetDescendants()) do if child:IsA("BasePart") then total = total + child.Position; count = count + 1 end end; if count > 0 then return total / count end; return part:GetPivot().Position end; if part:IsA("BasePart") then return part.Position end; return Vector3.new(0, 0, 0) end; function ESP:DrawHealthBar(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowHealthBars then return end; if not self.Callbacks.partToHealthCallback then return end; local healthInfo = self.Callbacks.partToHealthCallback(part) if not healthInfo then return end; local currentHealth = healthInfo.currentHealth or healthInfo[1] local maxHealth = healthInfo.maxHealth or healthInfo[2] if not currentHealth or not maxHealth or maxHealth <= 0 then return end; local healthPercent = math.clamp(currentHealth / maxHealth, 0, 1) local barWidth = boxWidth * healthPercent; local barPos = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight - self.Config.HealthBarHeight - 2) DrawingImmediate.Rectangle(barPos, Vector2.new(boxWidth, self.Config.HealthBarHeight), Color3.new(0.3, 0.3, 0.3), 0.8, 2, 1) if barWidth > 0 then DrawingImmediate.FilledRectangle(barPos, Vector2.new(barWidth, self.Config.HealthBarHeight), self:GetHealthColor(currentHealth, maxHealth), 1, 2) end; local healthText = string.format("%.0f/%.0f", currentHealth, maxHealth) local textPos = Vector2.new(screenPos.X, barPos.Y - 2) DrawingImmediate.OutlinedText(textPos, self.Config.NameFont, self.Config.FontSize - 2, Color3.new(1, 1, 1), 1, Color3.new(0, 0, 0), 1, healthText, true) end; function ESP:DrawTools(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowTools then return end; if not self.Callbacks.partToToolsToRenderCallback then return end; local tools = self.Callbacks.partToToolsToRenderCallback(part) if not tools or #tools == 0 then return end; local startX = screenPos.X - (boxWidth / 2) local startY = screenPos.Y + boxHeight + 5; local iconSize = self.Config.ToolIconSize; local spacing = 5; for i, tool in ipairs(tools) do local toolPart = tool.toolPart or tool[1] local toolName = tool.name or tool[2] or "Unknown" if toolPart and toolPart:IsA("BasePart") then local iconPos = Vector2.new(startX + (i - 1) * (iconSize + spacing), startY) DrawingImmediate.FilledRectangle(iconPos, Vector2.new(iconSize, iconSize), Color3.new(0.2, 0.2, 0.2), 0.8, 3) DrawingImmediate.Rectangle(iconPos, Vector2.new(iconSize, iconSize), Color3.new(1, 1, 1), 0.5, 3, 1) DrawingImmediate.OutlinedText(Vector2.new(iconPos.X + iconSize / 2, iconPos.Y + iconSize + 2), self.Config.NameFont, self.Config.FontSize - 2, Color3.new(1, 1, 1), 1, Color3.new(0, 0, 0), 1, toolName, true) local toolScreenPos = self:WorldToScreen(toolPart.Position) if toolScreenPos then DrawingImmediate.Line(screenPos, toolScreenPos, Color3.new(1, 1, 0), 0.5, 1) end end end end; function ESP:DrawNameAndDistance(part, screenPos, partName, distance) if not self.Config.ShowNames and not self.Config.ShowDistance then return end; local text = "" if self.Config.ShowNames then text = partName or "Unknown" end; if self.Config.ShowDistance and distance then local distText = string.format(" [%.0fm]", distance) text = text .. distText end; if text ~= "" then local textPos = Vector2.new(screenPos.X, screenPos.Y - 25) DrawingImmediate.OutlinedText(textPos, self.Config.NameFont, self.Config.FontSize, self.Config.NameColor, 1, Color3.new(0, 0, 0), 1, text, true) end end; function ESP:DrawBox(part, screenPos, boxWidth, boxHeight, distance) if not self.Config.ShowBoxes then return end; local topLeft = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight) local boxColor = self.Config.BoxColor; if self.Config.ShowHealthBars and self.Callbacks.partToHealthCallback then local healthInfo = self.Callbacks.partToHealthCallback(part) if healthInfo then local currentHealth = healthInfo.currentHealth or healthInfo[1] local maxHealth = healthInfo.maxHealth or healthInfo[2] if currentHealth and maxHealth then boxColor = self:GetHealthColor(currentHealth, maxHealth) end end end; DrawingImmediate.Rectangle(topLeft, Vector2.new(boxWidth, boxHeight), boxColor, 1, 0, self.Config.BoxThickness) local accentSize = math.min(10, boxWidth * 0.2) local accentColor = Color3.new(1, 1, 1) DrawingImmediate.Line(topLeft, Vector2.new(topLeft.X + accentSize, topLeft.Y), accentColor, 0.8, 2) DrawingImmediate.Line(topLeft, Vector2.new(topLeft.X, topLeft.Y + accentSize), accentColor, 0.8, 2) local topRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y) DrawingImmediate.Line(Vector2.new(topRight.X - accentSize, topRight.Y), topRight, accentColor, 0.8, 2) DrawingImmediate.Line(topRight, Vector2.new(topRight.X, topRight.Y + accentSize), accentColor, 0.8, 2) local bottomLeft = Vector2.new(topLeft.X, topLeft.Y + boxHeight) DrawingImmediate.Line(bottomLeft, Vector2.new(bottomLeft.X + accentSize, bottomLeft.Y), accentColor, 0.8, 2) DrawingImmediate.Line(bottomLeft, Vector2.new(bottomLeft.X, bottomLeft.Y - accentSize), accentColor, 0.8, 2) local bottomRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y + boxHeight) DrawingImmediate.Line(Vector2.new(bottomRight.X - accentSize, bottomRight.Y), bottomRight, accentColor, 0.8, 2) DrawingImmediate.Line(bottomRight, Vector2.new(bottomRight.X, bottomRight.Y - accentSize), accentColor, 0.8, 2) end; function ESP:_UpdateCache() local currentTime = tick() if currentTime - self._cache.lastUpdate < self._cache.updateInterval then return end; self._cache.lastUpdate = currentTime; self._cache.parts = {} self._cache.health = {} self._cache.tools = {} if self.Callbacks.getPartsToRenderCallback then local parts = self.Callbacks.getPartsToRenderCallback() if parts then for i, part in ipairs(parts) do self._cache.parts[#self._cache.parts + 1] = part; if self.Callbacks.partToHealthCallback then local health = self.Callbacks.partToHealthCallback(part) if health then self._cache.health[part] = health end end; if self.Callbacks.partToToolsToRenderCallback then local tools = self.Callbacks.partToToolsToRenderCallback(part) if tools then self._cache.tools[part] = tools end end end end end end; function ESP:_OnRender() if not self.Config.Enabled then return end; self:_UpdateCache() for _, part in ipairs(self._cache.parts) do if part and part.Parent then local partPosition = self:GetPartPosition(part) local screenPos, distance = self:WorldToScreen(partPosition) if screenPos and distance <= self.Config.MaxDistance then local boxWidth, boxHeight = self:GetPartBoxSize(part) local partName = part.Name; if part:IsA("Model") and part:FindFirstChild("Humanoid") then local humanoid = part:FindFirstChild("Humanoid") if humanoid.DisplayName and humanoid.DisplayName ~= "" then partName = humanoid.DisplayName end end; self:DrawBox(part, screenPos, boxWidth, boxHeight, distance) self:DrawHealthBar(part, screenPos, boxWidth, boxHeight) self:DrawNameAndDistance(part, screenPos, partName, distance) self:DrawTools(part, screenPos, boxWidth, boxHeight) end end end; for _, obj in ipairs(self._activeObjects) do if obj.type == "circle" and obj.position then local screenPos = self:WorldToScreen(obj.position) if screenPos then DrawingImmediate.Circle(screenPos, obj.radius, obj.color, 1, 32, 2) end elseif obj.type == "line" and obj.from and obj.to then local fromScreen = self:WorldToScreen(obj.from) local toScreen = self:WorldToScreen(obj.to) if fromScreen and toScreen then DrawingImmediate.Line(fromScreen, toScreen, obj.color, 1, obj.thickness or 1) end end end end; function ESP:SetGetPartsToRenderCallback(callback) self.Callbacks.getPartsToRenderCallback = callback end; function ESP:SetPartToHealthCallback(callback) self.Callbacks.partToHealthCallback = callback end; function ESP:SetPartToToolsToRenderCallback(callback) self.Callbacks.partToToolsToRenderCallback = callback end; function ESP:ClearCallbacks() self.Callbacks.getPartsToRenderCallback = nil; self.Callbacks.partToHealthCallback = nil; self.Callbacks.partToToolsToRenderCallback = nil end; function ESP:AddObject(object) self._activeObjects[#self._activeObjects + 1] = object; return object end; function ESP:RemoveObject(object) for i, obj in ipairs(self._activeObjects) do if obj == object then table.remove(self._activeObjects, i) break end end end; function ESP:ClearObjects() self._activeObjects = {} end; function ESP:SetConfig(newConfig) for k, v in pairs(newConfig) do self.Config[k] = v end end; function ESP:Toggle() self.Config.Enabled = not self.Config.Enabled; return self.Config.Enabled end; function ESP:Init() if self._signal then self:_Cleanup() end; self._signal = DrawingImmediate.GetPaint(self.Config.ZIndex) local connection = self._signal:Connect(function() self:_OnRender() end) self._connections[#self._connections + 1] = connection end; function ESP:_Cleanup() for _, conn in ipairs(self._connections) do conn:Disconnect() end; self._connections = {} self._signal = nil end; function ESP:Destroy() self:_Cleanup() self._activeObjects = {} self:ClearCallbacks() self._cache = { parts = {}, health = {}, tools = {}, lastUpdate = 0, updateInterval = 0.1 } end; function ESP:ForceUpdate() self._cache.lastUpdate = 0; self:_UpdateCache() end else if not Drawing then local drawingUI = Instance.new("ScreenGui", game:GetService("CoreGui")) drawingUI.Name = "Drawing" drawingUI.IgnoreGuiInset = true drawingUI.DisplayOrder = 0x7fffffff local drawingIndex = 0 local baseDrawingObj = setmetatable({ Visible = true, ZIndex = 0, Transparency = 1, Color = Color3.new(), Remove = function(self) setmetatable(self, nil) end, Destroy = function(self) setmetatable(self, nil) end }, { __add = function(t1, t2) local result = table.clone(t1) for index, value in t2 do result[index] = value end return result end }) local drawingFontsEnum = { [0] = Font.fromEnum(Enum.Font.Roboto), [1] = Font.fromEnum(Enum.Font.Legacy), [2] = Font.fromEnum(Enum.Font.SourceSans), [3] = Font.fromEnum(Enum.Font.RobotoMono), } local function convertTransparency(transparency) return math.clamp(1 - transparency, 0, 1) end local DrawingLib = {} DrawingLib.Fonts = { ["UI"] = 0, ["System"] = 1, ["Plex"] = 2, ["Monospace"] = 3 } function DrawingLib.new(drawingType) drawingIndex += 1 if drawingType == "Line" then local lineObj = ({ From = Vector2.zero, To = Vector2.zero, Thickness = 1 } + baseDrawingObj) local lineFrame = Instance.new("Frame") lineFrame.Name = drawingIndex lineFrame.AnchorPoint = (Vector2.one * .5) lineFrame.BorderSizePixel = 0 lineFrame.BackgroundColor3 = lineObj.Color lineFrame.Visible = lineObj.Visible lineFrame.ZIndex = lineObj.ZIndex lineFrame.BackgroundTransparency = convertTransparency(lineObj.Transparency) lineFrame.Size = UDim2.new() lineFrame.Parent = drawingUI return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(lineObj[index]) == "nil" then return end if index == "From" then local direction = (lineObj.To - value) local center = (lineObj.To + value) / 2 local distance = direction.Magnitude local theta = math.deg(math.atan2(direction.Y, direction.X)) lineFrame.Position = UDim2.fromOffset(center.X, center.Y) lineFrame.Rotation = theta lineFrame.Size = UDim2.fromOffset(distance, lineObj.Thickness) elseif index == "To" then local direction = (value - lineObj.From) local center = (value + lineObj.From) / 2 local distance = direction.Magnitude local theta = math.deg(math.atan2(direction.Y, direction.X)) lineFrame.Position = UDim2.fromOffset(center.X, center.Y) lineFrame.Rotation = theta lineFrame.Size = UDim2.fromOffset(distance, lineObj.Thickness) elseif index == "Thickness" then local distance = (lineObj.To - lineObj.From).Magnitude lineFrame.Size = UDim2.fromOffset(distance, value) elseif index == "Visible" then lineFrame.Visible = value elseif index == "ZIndex" then lineFrame.ZIndex = value elseif index == "Transparency" then lineFrame.BackgroundTransparency = convertTransparency(value) elseif index == "Color" then lineFrame.BackgroundColor3 = value end lineObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() lineFrame:Destroy() lineObj.Remove(self) return lineObj:Remove() end end return lineObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Text" then local textObj = ({ Text = "", Font = DrawingLib.Fonts.UI, Size = 0, Position = Vector2.zero, Center = false, Outline = false, OutlineColor = Color3.new() } + baseDrawingObj) local textLabel, uiStroke = Instance.new("TextLabel"), Instance.new("UIStroke") textLabel.Name = drawingIndex textLabel.AnchorPoint = (Vector2.one * .5) textLabel.BorderSizePixel = 0 textLabel.BackgroundTransparency = 1 textLabel.Visible = textObj.Visible textLabel.TextColor3 = textObj.Color textLabel.TextTransparency = convertTransparency(textObj.Transparency) textLabel.ZIndex = textObj.ZIndex textLabel.FontFace = drawingFontsEnum[textObj.Font] textLabel.TextSize = textObj.Size textLabel:GetPropertyChangedSignal("TextBounds"):Connect(function() local textBounds = textLabel.TextBounds local offset = textBounds / 2 textLabel.Size = UDim2.fromOffset(textBounds.X, textBounds.Y) textLabel.Position = UDim2.fromOffset(textObj.Position.X + (if not textObj.Center then offset.X else 0), textObj.Position.Y + offset.Y) end) uiStroke.Thickness = 1 uiStroke.Enabled = textObj.Outline uiStroke.Color = textObj.Color textLabel.Parent, uiStroke.Parent = drawingUI, textLabel return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(textObj[index]) == "nil" then return end if index == "Text" then textLabel.Text = value elseif index == "Font" then value = math.clamp(value, 0, 3) textLabel.FontFace = drawingFontsEnum[value] elseif index == "Size" then textLabel.TextSize = value elseif index == "Position" then local offset = textLabel.TextBounds / 2 textLabel.Position = UDim2.fromOffset(value.X + (if not textObj.Center then offset.X else 0), value.Y + offset.Y) elseif index == "Center" then local position = ( if value then workspace.CurrentCamera.ViewportSize / 2 else textObj.Position ) textLabel.Position = UDim2.fromOffset(position.X, position.Y) elseif index == "Outline" then uiStroke.Enabled = value elseif index == "OutlineColor" then uiStroke.Color = value elseif index == "Visible" then textLabel.Visible = value elseif index == "ZIndex" then textLabel.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) textLabel.TextTransparency = transparency uiStroke.Transparency = transparency elseif index == "Color" then textLabel.TextColor3 = value end textObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() textLabel:Destroy() textObj.Remove(self) return textObj:Remove() end elseif index == "TextBounds" then return textLabel.TextBounds end return textObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Circle" then local circleObj = ({ Radius = 150, Position = Vector2.zero, Thickness = .7, Filled = false } + baseDrawingObj) local circleFrame, uiCorner, uiStroke = Instance.new("Frame"), Instance.new("UICorner"), Instance.new("UIStroke") circleFrame.Name = drawingIndex circleFrame.AnchorPoint = (Vector2.one * .5) circleFrame.BorderSizePixel = 0 circleFrame.BackgroundTransparency = (if circleObj.Filled then convertTransparency(circleObj.Transparency) else 1) circleFrame.BackgroundColor3 = circleObj.Color circleFrame.Visible = circleObj.Visible circleFrame.ZIndex = circleObj.ZIndex uiCorner.CornerRadius = UDim.new(1, 0) circleFrame.Size = UDim2.fromOffset(circleObj.Radius, circleObj.Radius) uiStroke.Thickness = circleObj.Thickness uiStroke.Enabled = not circleObj.Filled uiStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border circleFrame.Parent, uiCorner.Parent, uiStroke.Parent = drawingUI, circleFrame, circleFrame return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(circleObj[index]) == "nil" then return end if index == "Radius" then local radius = value * 2 circleFrame.Size = UDim2.fromOffset(radius, radius) elseif index == "Position" then circleFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Thickness" then value = math.clamp(value, .6, 0x7fffffff) uiStroke.Thickness = value elseif index == "Filled" then circleFrame.BackgroundTransparency = (if value then convertTransparency(circleObj.Transparency) else 1) uiStroke.Enabled = not value elseif index == "Visible" then circleFrame.Visible = value elseif index == "ZIndex" then circleFrame.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) circleFrame.BackgroundTransparency = (if circleObj.Filled then transparency else 1) uiStroke.Transparency = transparency elseif index == "Color" then circleFrame.BackgroundColor3 = value uiStroke.Color = value end circleObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() circleFrame:Destroy() circleObj.Remove(self) return circleObj:Remove() end end return circleObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Square" then local squareObj = ({ Size = Vector2.zero, Position = Vector2.zero, Thickness = .7, Filled = false } + baseDrawingObj) local squareFrame, uiStroke = Instance.new("Frame"), Instance.new("UIStroke") squareFrame.Name = drawingIndex squareFrame.BorderSizePixel = 0 squareFrame.BackgroundTransparency = (if squareObj.Filled then convertTransparency(squareObj.Transparency) else 1) squareFrame.ZIndex = squareObj.ZIndex squareFrame.BackgroundColor3 = squareObj.Color squareFrame.Visible = squareObj.Visible uiStroke.Thickness = squareObj.Thickness uiStroke.Enabled = not squareObj.Filled uiStroke.LineJoinMode = Enum.LineJoinMode.Miter squareFrame.Parent, uiStroke.Parent = drawingUI, squareFrame return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(squareObj[index]) == "nil" then return end if index == "Size" then squareFrame.Size = UDim2.fromOffset(value.X, value.Y) elseif index == "Position" then squareFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Thickness" then value = math.clamp(value, 0.6, 0x7fffffff) uiStroke.Thickness = value elseif index == "Filled" then squareFrame.BackgroundTransparency = (if value then convertTransparency(squareObj.Transparency) else 1) uiStroke.Enabled = not value elseif index == "Visible" then squareFrame.Visible = value elseif index == "ZIndex" then squareFrame.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) squareFrame.BackgroundTransparency = (if squareObj.Filled then transparency else 1) uiStroke.Transparency = transparency elseif index == "Color" then uiStroke.Color = value squareFrame.BackgroundColor3 = value end squareObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() squareFrame:Destroy() squareObj.Remove(self) return squareObj:Remove() end end return squareObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Image" then local imageObj = ({ Data = "", Size = Vector2.zero, Position = Vector2.zero } + baseDrawingObj) local imageFrame = Instance.new("ImageLabel") imageFrame.Name = drawingIndex imageFrame.BorderSizePixel = 0 imageFrame.ScaleType = Enum.ScaleType.Stretch imageFrame.BackgroundTransparency = 1 imageFrame.Visible = imageObj.Visible imageFrame.ZIndex = imageObj.ZIndex imageFrame.ImageTransparency = convertTransparency(imageObj.Transparency) imageFrame.ImageColor3 = imageObj.Color imageFrame.Parent = drawingUI return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(imageObj[index]) == "nil" then return end if index == "Data" then imageFrame.Image = value elseif index == "Size" then imageFrame.Size = UDim2.fromOffset(value.X, value.Y) elseif index == "Position" then imageFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Visible" then imageFrame.Visible = value elseif index == "ZIndex" then imageFrame.ZIndex = value elseif index == "Transparency" then imageFrame.ImageTransparency = convertTransparency(value) elseif index == "Color" then imageFrame.ImageColor3 = value end imageObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() imageFrame:Destroy() imageObj.Remove(self) return imageObj:Remove() end end return imageObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Quad" then local QuadProperties = ({ Thickness = 1, PointA = Vector2.new(); PointB = Vector2.new(); PointC = Vector2.new(); PointD = Vector2.new(); Filled = false; } + baseDrawingObj) local PointA = DrawingLib.new("Line") local PointB = DrawingLib.new("Line") local PointC = DrawingLib.new("Line") local PointD = DrawingLib.new("Line") return setmetatable({__type = "Drawing Object"}, { __newindex = function(self, Property, Value) if Property == "Thickness" then PointA.Thickness = Value PointB.Thickness = Value PointC.Thickness = Value PointD.Thickness = Value end if Property == "PointA" then PointA.From = Value PointB.To = Value end if Property == "PointB" then PointB.From = Value PointC.To = Value end if Property == "PointC" then PointC.From = Value PointD.To = Value end if Property == "PointD" then PointD.From = Value PointA.To = Value end if Property == "Visible" then PointA.Visible = true PointB.Visible = true PointC.Visible = true PointD.Visible = true end if Property == "Filled" then PointA.BackgroundTransparency = 1 PointB.BackgroundTransparency = 1 PointC.BackgroundTransparency = 1 PointD.BackgroundTransparency = 1 end if Property == "Color" then PointA.Color = Value PointB.Color = Value PointC.Color = Value PointD.Color = Value end if (Property == "ZIndex") then PointA.ZIndex = Value PointB.ZIndex = Value PointC.ZIndex = Value PointD.ZIndex = Value end end, __index = function(self, Property) if (string.lower(tostring(Property)) == "remove") then return (function() PointA:Remove(); PointB:Remove(); PointC:Remove(); PointD:Remove(); end) end return QuadProperties[Property] end }); elseif drawingType == "Triangle" then local triangleObj = ({ PointA = Vector2.zero, PointB = Vector2.zero, PointC = Vector2.zero, Thickness = 1, Filled = false } + baseDrawingObj) local _linePoints = {} _linePoints.A = DrawingLib.new("Line") _linePoints.B = DrawingLib.new("Line") _linePoints.C = DrawingLib.new("Line") return setmetatable({__type = "Drawing Object"}, { __tostring = function() return "Drawing" end, __newindex = function(_, index, value) if typeof(triangleObj[index]) == "nil" then return end if index == "PointA" then _linePoints.A.From = value _linePoints.B.To = value elseif index == "PointB" then _linePoints.B.From = value _linePoints.C.To = value elseif index == "PointC" then _linePoints.C.From = value _linePoints.A.To = value elseif (index == "Thickness" or index == "Visible" or index == "Color" or index == "ZIndex") then for _, linePoint in _linePoints do linePoint[index] = value end elseif index == "Filled" then _linePoints.BackgroundTransparency = 1 end triangleObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() for _, linePoint in _linePoints do linePoint:Remove() end triangleObj.Remove(self) return triangleObj:Remove() end end return triangleObj[index] end }) end end if not getgenv then getfenv().getgenv = function() return getfenv(3) or getfenv(2) end end local isrenderobj = function(obj) local s, r = pcall(function() return obj.__type == "Drawing Object" end) return s and r end getgenv().isrenderobj = isrenderobj getgenv().cleardrawcache = function() drawingUI:ClearAllChildren() end getgenv().getrenderproperty = function(obj, prop) assert(isrenderobj(obj), "Object must be a Drawing", 3) return obj[prop] end getgenv().setrenderproperty = function(obj, prop, val) assert(isrenderobj(obj), "Object must be a Drawing", 3) obj[prop] = val end getgenv().Drawing = DrawingLib end function ESP:WorldToScreen(worldPosition) local camera = workspace.CurrentCamera; if not camera then return nil end; local vector, onScreen = camera:WorldToViewportPoint(worldPosition) if onScreen and vector.Z > 0 then return Vector2.new(vector.X, vector.Y), vector.Z end; return nil, nil end; function ESP:GetHealthColor(currentHealth, maxHealth) if not currentHealth or not maxHealth or maxHealth <= 0 then return Color3.new(1, 1, 1) end; local percent = currentHealth / maxHealth; if percent > 0.7 then return Color3.new(0, 1, 0) elseif percent > 0.3 then return Color3.new(1, 1, 0) else return Color3.new(1, 0, 0) end end; function ESP:GetPartBoxSize(part) if not part then return 2, 2 end; if part:IsA("Model") then local size = part:GetExtentsSize() return size.X * 2, size.Y * 2 end; if part:IsA("BasePart") then local size = part.Size; return size.X, size.Y end; return 2, 2 end; function ESP:GetPartPosition(part) if part:IsA("Model") then local primary = part.PrimaryPart; if primary then return primary.Position end; local total = Vector3.new(0, 0, 0) local count = 0; for _, child in ipairs(part:GetDescendants()) do if child:IsA("BasePart") then total = total + child.Position; count = count + 1 end end; if count > 0 then return total / count end; return part:GetPivot().Position end; if part:IsA("BasePart") then return part.Position end; return Vector3.new(0, 0, 0) end; function ESP:_CreateDrawingObject(type, properties) local obj = Drawing.new(type) for k, v in pairs(properties) do obj[k] = v end; obj.Visible = true; obj.ZIndex = self.Config.ZIndex; table.insert(self._drawingObjects, obj) return obj end; function ESP:_UpdateDrawingObject(obj, properties) for k, v in pairs(properties) do obj[k] = v end end; function ESP:_ClearDrawingObjects() for _, obj in ipairs(self._drawingObjects) do obj:Remove() end; self._drawingObjects = {} end; function ESP:DrawHealthBar(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowHealthBars then return end; if not self.Callbacks.partToHealthCallback then return end; local healthInfo = self.Callbacks.partToHealthCallback(part) if not healthInfo then return end; local currentHealth = healthInfo.currentHealth or healthInfo[1] local maxHealth = healthInfo.maxHealth or healthInfo[2] if not currentHealth or not maxHealth or maxHealth <= 0 then return end; local healthPercent = math.clamp(currentHealth / maxHealth, 0, 1) local barWidth = boxWidth * healthPercent; local barPos = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight - self.Config.HealthBarHeight - 2) local bgBar = self:_CreateDrawingObject("Square", { Position = barPos, Size = Vector2.new(boxWidth, self.Config.HealthBarHeight), Color = Color3.new(0.3, 0.3, 0.3), Transparency = 0.2, Thickness = 1, Filled = true }) if barWidth > 0 then local healthBar = self:_CreateDrawingObject("Square", { Position = barPos, Size = Vector2.new(barWidth, self.Config.HealthBarHeight), Color = self:GetHealthColor(currentHealth, maxHealth), Transparency = 0, Thickness = 1, Filled = true }) end; local healthText = string.format("%.0f/%.0f", currentHealth, maxHealth) local textPos = Vector2.new(screenPos.X, barPos.Y - 2) local textObj = self:_CreateDrawingObject("Text", { Position = textPos, Text = healthText, Color = Color3.new(1, 1, 1), Size = self.Config.FontSize - 2, Center = true, Font = self.Config.NameFont, Transparency = 0 }) local outlineObj = self:_CreateDrawingObject("Text", { Position = Vector2.new(textPos.X + 1, textPos.Y + 1), Text = healthText, Color = Color3.new(0, 0, 0), Size = self.Config.FontSize - 2, Center = true, Font = self.Config.NameFont, Transparency = 0 }) end; function ESP:DrawTools(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowTools then return end; if not self.Callbacks.partToToolsToRenderCallback then return end; local tools = self.Callbacks.partToToolsToRenderCallback(part) if not tools or #tools == 0 then return end; local startX = screenPos.X - (boxWidth / 2) local startY = screenPos.Y + boxHeight + 5; local iconSize = self.Config.ToolIconSize; local spacing = 5; for i, tool in ipairs(tools) do local toolPart = tool.toolPart or tool[1] local toolName = tool.name or tool[2] or "Unknown" if toolPart and toolPart:IsA("BasePart") then local iconPos = Vector2.new(startX + (i - 1) * (iconSize + spacing), startY) self:_CreateDrawingObject("Square", { Position = iconPos, Size = Vector2.new(iconSize, iconSize), Color = Color3.new(0.2, 0.2, 0.2), Transparency = 0.2, Thickness = 1, Filled = true }) self:_CreateDrawingObject("Square", { Position = iconPos, Size = Vector2.new(iconSize, iconSize), Color = Color3.new(1, 1, 1), Transparency = 0.5, Thickness = 1, Filled = false }) local textPos = Vector2.new(iconPos.X + iconSize / 2, iconPos.Y + iconSize + 2) self:_CreateDrawingObject("Text", { Position = textPos, Text = toolName, Color = Color3.new(1, 1, 1), Size = self.Config.FontSize - 2, Center = true, Font = self.Config.NameFont, Transparency = 0 }) local toolScreenPos = self:WorldToScreen(toolPart.Position) if toolScreenPos then self:_CreateDrawingObject("Line", { From = screenPos, To = toolScreenPos, Color = Color3.new(1, 1, 0), Transparency = 0.5, Thickness = 1 }) end end end end; function ESP:DrawNameAndDistance(part, screenPos, partName, distance) if not self.Config.ShowNames and not self.Config.ShowDistance then return end; local text = "" if self.Config.ShowNames then text = partName or "Unknown" end; if self.Config.ShowDistance and distance then local distText = string.format(" [%.0fm]", distance) text = text .. distText end; if text ~= "" then local textPos = Vector2.new(screenPos.X, screenPos.Y - 25) self:_CreateDrawingObject("Text", { Position = Vector2.new(textPos.X + 1, textPos.Y + 1), Text = text, Color = Color3.new(0, 0, 0), Size = self.Config.FontSize, Center = true, Font = self.Config.NameFont, Transparency = 0 }) self:_CreateDrawingObject("Text", { Position = textPos, Text = text, Color = self.Config.NameColor, Size = self.Config.FontSize, Center = true, Font = self.Config.NameFont, Transparency = 0 }) end end; function ESP:DrawBox(part, screenPos, boxWidth, boxHeight, distance) if not self.Config.ShowBoxes then return end; local topLeft = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight) local boxColor = self.Config.BoxColor; if self.Config.ShowHealthBars and self.Callbacks.partToHealthCallback then local healthInfo = self.Callbacks.partToHealthCallback(part) if healthInfo then local currentHealth = healthInfo.currentHealth or healthInfo[1] local maxHealth = healthInfo.maxHealth or healthInfo[2] if currentHealth and maxHealth then boxColor = self:GetHealthColor(currentHealth, maxHealth) end end end; self:_CreateDrawingObject("Square", { Position = topLeft, Size = Vector2.new(boxWidth, boxHeight), Color = boxColor, Transparency = 0, Thickness = self.Config.BoxThickness, Filled = false }) local accentSize = math.min(10, boxWidth * 0.2) local accentColor = Color3.new(1, 1, 1) self:_CreateDrawingObject("Line", { From = topLeft, To = Vector2.new(topLeft.X + accentSize, topLeft.Y), Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = topLeft, To = Vector2.new(topLeft.X, topLeft.Y + accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local topRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y) self:_CreateDrawingObject("Line", { From = Vector2.new(topRight.X - accentSize, topRight.Y), To = topRight, Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = topRight, To = Vector2.new(topRight.X, topRight.Y + accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local bottomLeft = Vector2.new(topLeft.X, topLeft.Y + boxHeight) self:_CreateDrawingObject("Line", { From = bottomLeft, To = Vector2.new(bottomLeft.X + accentSize, bottomLeft.Y), Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = bottomLeft, To = Vector2.new(bottomLeft.X, bottomLeft.Y - accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local bottomRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y + boxHeight) self:_CreateDrawingObject("Line", { From = Vector2.new(bottomRight.X - accentSize, bottomRight.Y), To = bottomRight, Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = bottomRight, To = Vector2.new(bottomRight.X, bottomRight.Y - accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) end; function ESP:_UpdateCache() local currentTime = tick() if currentTime - self._cache.lastUpdate < self._cache.updateInterval then return end; self._cache.lastUpdate = currentTime; self._cache.parts = {} self._cache.health = {} self._cache.tools = {} if self.Callbacks.getPartsToRenderCallback then local parts = self.Callbacks.getPartsToRenderCallback() if parts then for i, part in ipairs(parts) do self._cache.parts[#self._cache.parts + 1] = part; if self.Callbacks.partToHealthCallback then local health = self.Callbacks.partToHealthCallback(part) if health then self._cache.health[part] = health end end; if self.Callbacks.partToToolsToRenderCallback then local tools = self.Callbacks.partToToolsToRenderCallback(part) if tools then self._cache.tools[part] = tools end end end end end end; function ESP:_OnRender() if not self.Config.Enabled then return end; self:_ClearDrawingObjects() self:_UpdateCache() for _, part in ipairs(self._cache.parts) do if part and part.Parent then local partPosition = self:GetPartPosition(part) local screenPos, distance = self:WorldToScreen(partPosition) if screenPos and distance <= self.Config.MaxDistance then local boxWidth, boxHeight = self:GetPartBoxSize(part) local partName = part.Name; if part:IsA("Model") and part:FindFirstChild("Humanoid") then local humanoid = part:FindFirstChild("Humanoid") if humanoid.DisplayName and humanoid.DisplayName ~= "" then partName = humanoid.DisplayName end end; self:DrawBox(part, screenPos, boxWidth, boxHeight, distance) self:DrawHealthBar(part, screenPos, boxWidth, boxHeight) self:DrawNameAndDistance(part, screenPos, partName, distance) self:DrawTools(part, screenPos, boxWidth, boxHeight) end end end; for _, obj in ipairs(self._activeObjects) do if obj.type == "circle" and obj.position then local screenPos = self:WorldToScreen(obj.position) if screenPos then self:_CreateDrawingObject("Circle", { Position = screenPos, Radius = obj.radius, Color = obj.color, Transparency = obj.transparency or 0, Thickness = obj.thickness or 2, Filled = obj.filled or false, NumSides = 32 }) end elseif obj.type == "line" and obj.from and obj.to then local fromScreen = self:WorldToScreen(obj.from) local toScreen = self:WorldToScreen(obj.to) if fromScreen and toScreen then self:_CreateDrawingObject("Line", { From = fromScreen, To = toScreen, Color = obj.color, Transparency = obj.transparency or 0, Thickness = obj.thickness or 1 }) end end end end; function ESP:SetGetPartsToRenderCallback(callback) self.Callbacks.getPartsToRenderCallback = callback end; function ESP:SetPartToHealthCallback(callback) self.Callbacks.partToHealthCallback = callback end; function ESP:SetPartToToolsToRenderCallback(callback) self.Callbacks.partToToolsToRenderCallback = callback end; function ESP:ClearCallbacks() self.Callbacks.getPartsToRenderCallback = nil; self.Callbacks.partToHealthCallback = nil; self.Callbacks.partToToolsToRenderCallback = nil end; function ESP:AddObject(object) self._activeObjects[#self._activeObjects + 1] = object; return object end; function ESP:RemoveObject(object) for i, obj in ipairs(self._activeObjects) do if obj == object then table.remove(self._activeObjects, i) break end end end; function ESP:ClearObjects() self._activeObjects = {} end; function ESP:SetConfig(newConfig) for k, v in pairs(newConfig) do self.Config[k] = v end end; function ESP:Toggle() self.Config.Enabled = not self.Config.Enabled; return self.Config.Enabled end; function ESP:Init() if self._renderConnection then self:_Cleanup() end; self._renderConnection = game:GetService("RunService").RenderStepped:Connect(function() self:_OnRender() end) end; function ESP:_Cleanup() if self._renderConnection then self._renderConnection:Disconnect() self._renderConnection = nil end; self:_ClearDrawingObjects() end; function ESP:Destroy() self:_Cleanup() self._activeObjects = {} self:ClearCallbacks() self._cache = { parts = {}, health = {}, tools = {}, lastUpdate = 0, updateInterval = 0.1 } end; function ESP:ForceUpdate() self._cache.lastUpdate = 0; self:_UpdateCache() end; end local Config = { Enabled = true, ShowHealthBars = false, ShowNames = false, ShowBoxes = true, ShowDistance = false, ShowTools = false, BoxThickness = 2, NameFont = 1, FontSize = 14, NameColor = Color3.new(1, 0, 0), BoxColor = Color3.new(1, 0, 0), HealthBarWidth = 2, HealthBarHeight = 12, MaxDistance = 999, ToolIconSize = 16, ZIndex = 2, } ESP:SetConfig(Config) local function GetEnemySoldiers() local Enemies, FirstPersonViewID = {}, ClientState.fpv_sol_id local MyTeam = SoldierTeams[FirstPersonViewID] for PlayerID, IsSpawned in SoldiersSpawned do if IsSpawned and SoldiersAlive[PlayerID] and PlayerID ~= FirstPersonViewID then local EnemyTeam = SoldierTeams[PlayerID] if EnemyTeam and EnemyTeam ~= MyTeam then local Character = SoldierModels[PlayerID] if Character then table.insert(Enemies, { ID = PlayerID, Character = Character, Team = EnemyTeam, }) end end end end return Enemies end ESP:SetGetPartsToRenderCallback(function() local Parts, Enemies = {}, GetEnemySoldiers() for _, Enemy in Enemies do if Enemy.Character and Enemy.Character.PrimaryPart then table.insert(Parts, Enemy.Character) end end return Parts end) ESP:Init() ]])