-- ============================================================ ESP
local espGui, espHolder
do
local function container()
local ok, hui = pcall(gethui)
if ok and typeof(hui) == "Instance" then return hui end
local ok2, core = pcall(function() return game:GetService("CoreGui") end)
if ok2 and core then return core end
return LP:FindFirstChildOfClass("PlayerGui")
end
espGui = Instance.new("ScreenGui")
espGui.Name = "BoulderEsp"
espGui.ResetOnSpawn = false
espGui.IgnoreGuiInset = true
espGui.DisplayOrder = 100
espGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
pcall(function() espGui.Parent = container() end)
espHolder = Instance.new("Folder")
espHolder.Name = "targets"
espHolder.Parent = espGui
end
STATE.drawings = {}
-- One drawing per animal, owned by this table. The previous version only ever hid a
-- drawing while its model was still being tracked, so an animal that despawned left its
-- box painted on the screen for the rest of the match. Now a drawing whose model is gone
-- is freed in the same pass that draws the rest.
local function newDrawing(model)
local box = Instance.new("Frame")
box.Name = "box"
box.BackgroundTransparency = 1
box.BorderSizePixel = 0
box.Visible = false
box.Parent = espHolder
local sides, corners = {}, {}
for i = 1, 4 do
local line = Instance.new("Frame")
line.Name = "side" .. i
line.BorderSizePixel = 0
line.Parent = box
sides[i] = line
end
for i = 1, 8 do
local line = Instance.new("Frame")
line.Name = "corner" .. i
line.BorderSizePixel = 0
line.Parent = box
corners[i] = line
end
local label = Instance.new("TextLabel")
label.Name = "name"
label.BackgroundTransparency = 1
label.Font = Enum.Font.GothamMedium
label.TextSize = 12
label.RichText = true
label.TextXAlignment = Enum.TextXAlignment.Center
label.TextYAlignment = Enum.TextYAlignment.Bottom
label.TextStrokeTransparency = 0.55
label.TextStrokeColor3 = Color3.new(0, 0, 0)
label.Visible = false
label.Parent = espHolder
local highlight = Instance.new("Highlight")
highlight.FillTransparency = 0.82
highlight.OutlineTransparency = 0.35
highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
highlight.Enabled = false
highlight.Adornee = model
highlight.Parent = espHolder
return { box = box, sides = sides, corners = corners, label = label, highlight = highlight }
end
local function freeDrawing(dr)
if dr.box then dr.box:Destroy() end
if dr.label then dr.label:Destroy() end
if dr.highlight then dr.highlight:Destroy() end
end
local function drawingFor(model)
local dr = STATE.drawings[model]
if dr and dr.box and dr.box.Parent and dr.label and dr.label.Parent then return dr end
dr = newDrawing(model)
STATE.drawings[model] = dr
return dr
end
-- Screen-space box of the volume a bullet has to pass through. The centre has to be in
-- front of the camera, otherwise a corner behind the near plane stretches the box across
-- the whole screen.
local function projectBox(model, rec)
local part = rec.part
if not (part and part.Parent) then return nil end
local cf, size
if part:IsA("BasePart") then
cf, size = part.CFrame, part.Size
else
local ok, c, s = pcall(function() return model:GetBoundingBox() end)
if not ok or not c then return nil end
cf, size = c, s
end
local centre = Camera:WorldToViewportPoint(cf.Position)
if centre.Z <= 0 then return nil end
local minX, minY = math.huge, math.huge
local maxX, maxY = -math.huge, -math.huge
local any = false
for ox = -1, 1, 2 do
for oy = -1, 1, 2 do
for oz = -1, 1, 2 do
local world = cf * Vector3.new(ox * size.X * 0.5, oy * size.Y * 0.5, oz * size.Z * 0.5)
local sp = Camera:WorldToViewportPoint(world)
if sp.Z > 0 then
any = true
minX, maxX = math.min(minX, sp.X), math.max(maxX, sp.X)
minY, maxY = math.min(minY, sp.Y), math.max(maxY, sp.Y)
end
end
end
end
if not any or maxX - minX < 0.5 or maxY - minY < 0.5 then return nil end
return minX, minY, maxX, maxY
end
local function colourFor(rec)
if rec.kind == "dead" then return CONFIG.esp.deadColor end
if rec.kind == "mount" or rec.kind == "dog" then return Color3.fromRGB(240, 190, 90) end
return CONFIG.esp.color
end
local nameCache = {}
local function prettyName(model)
local cached = nameCache[model.Name]
if cached then return cached end
local out = model:GetAttribute("DisplayName")
if not out or out == "" then
out = tostring(model.Name):gsub("(%l)(%u)", "%1 %2")
end
nameCache[model.Name] = out
return out
end
local function drawEsp()
local drawn = {}
local camPos = Camera.CFrame.Position
if CONFIG.esp.enabled then
for model, rec in pairs(STATE.tracks) do
if rec.part and rec.part.Parent and model.Parent and trackAllowed(rec) then
local dist = (rec.aimPos - camPos).Magnitude
if dist <= CONFIG.esp.maxDistance then
local minX, minY, maxX, maxY = projectBox(model, rec)
if minX then
drawn[model] = true
local dr = drawingFor(model)
local col = colourFor(rec)
local w, h = maxX - minX, maxY - minY
local t = CONFIG.esp.thickness
-- fade with range so a valley full of animals stays readable up close
local fade = math.clamp((dist / math.max(CONFIG.esp.maxDistance, 1)) * 0.55, 0, 0.55)
local style = CONFIG.esp.boxStyle
local showBox = style ~= "Corners"
local showCorners = style ~= "Box"
dr.box.Visible = true
dr.box.Position = UDim2.fromOffset(minX, minY)
dr.box.Size = UDim2.fromOffset(math.max(w, 1), math.max(h, 1))
local sideRects = {
{ 0, 0, w, t }, { 0, h - t, w, t }, { 0, 0, t, h }, { w - t, 0, t, h },
}
for i, s in ipairs(sideRects) do
local line = dr.sides[i]
line.Visible = showBox
line.BackgroundColor3 = col
line.BackgroundTransparency = fade
line.Position = UDim2.fromOffset(s[1], s[2])
line.Size = UDim2.fromOffset(s[3], s[4])
end
local cw = math.clamp(w * 0.22, 3, 11)
local ch = math.clamp(h * 0.22, 3, 11)
local cornerRects = {
{ 0, 0, cw, t }, { 0, 0, t, ch },
{ w - cw, 0, cw, t }, { w - t, 0, t, ch },
{ 0, h - t, cw, t }, { 0, h - ch, t, ch },
{ w - cw, h - t, cw, t }, { w - t, h - ch, t, ch },
}
for i, s in ipairs(cornerRects) do
local line = dr.corners[i]
line.Visible = showCorners
line.BackgroundColor3 = col
line.BackgroundTransparency = fade
line.Position = UDim2.fromOffset(s[1], s[2])
line.Size = UDim2.fromOffset(s[3], s[4])
end
dr.highlight.Enabled = CONFIG.esp.fill
dr.highlight.FillColor = col
dr.highlight.OutlineColor = col
dr.highlight.FillTransparency = math.clamp(0.74 + fade * 0.4, 0, 0.95)
dr.highlight.OutlineTransparency = math.clamp(0.25 + fade, 0, 0.95)
local bits = {}
if CONFIG.esp.name then
bits[#bits + 1] = string.format("%s", prettyName(model))
end
if CONFIG.esp.info and rec.kind == "animal" then
local variant = model:GetAttribute("Variant")
local sex = model:GetAttribute("Sex")
local extra = {}
if variant and variant ~= "Default" then extra[#extra + 1] = tostring(variant) end
if sex then extra[#extra + 1] = tostring(sex) end
if #extra > 0 then bits[#bits + 1] = table.concat(extra, " ") end
end
if CONFIG.esp.distance then
bits[#bits + 1] = string.format("%dm",
math.floor(dist * 0.28))
end
local text = table.concat(bits, " ")
dr.label.Visible = text ~= ""
dr.label.Text = text
dr.label.TextColor3 = col
dr.label.TextSize = CONFIG.esp.textSize
dr.label.TextTransparency = fade * 0.5
dr.label.Position = UDim2.fromOffset(minX - 60, minY - 17)
dr.label.Size = UDim2.fromOffset(w + 120, 16)
end
end
end
end
end
-- Whatever was not drawn this frame is either hidden (still alive, off screen or out of
-- range) or freed (the animal is gone). Nothing can be left stranded on the screen.
for model, dr in pairs(STATE.drawings) do
if not drawn[model] then
if not model.Parent or not STATE.tracks[model] then
freeDrawing(dr)
STATE.drawings[model] = nil
else
dr.box.Visible = false
dr.label.Visible = false
dr.highlight.Enabled = false
end
end
end
end