Загрузка данных


--[[
    Blood Engine | LinoriaLib
    Полностью переписанная версия с корректным API LinoriaLib
]]

--// ==================== ENVIRONMENT ====================
local cloneref = cloneref or function(o) return o end
local Players = cloneref(game:GetService("Players"))
local Lighting = cloneref(game:GetService("Lighting"))
local RunService = cloneref(game:GetService("RunService"))
local UserInputService = cloneref(game:GetService("UserInputService"))
local TweenService = cloneref(game:GetService("TweenService"))
local CoreGui = cloneref(game:GetService("CoreGui"))

local LocalPlayer = Players.LocalPlayer
local Camera = workspace.CurrentCamera

--// ==================== LINORIA LIBRARY ====================
local repo = "https://raw.githubusercontent.com/violin-suzutsuki/LinoriaLib/main/"
local Library = loadstring(game:HttpGet(repo .. "Library.lua"))()
local ThemeManager = loadstring(game:HttpGet(repo .. "addons/ThemeManager.lua"))()
local SaveManager = loadstring(game:HttpGet(repo .. "addons/SaveManager.lua"))()

--// ==================== WINDOW ====================
local Options = Library.Options
local Toggles = Library.Toggles

local Window = Library:CreateWindow({
    Title = "Blood Engine",
    Center = true,
    AutoShow = true,
    TabPadding = 8,
    MenuFadeTime = 0.2,
    Resizable = true,
    Size = UDim2.fromOffset(600, 500),
})

--// ==================== TABS ====================
local Tabs = {
    Legit    = Window:AddTab("Legit"),
    Visuals  = Window:AddTab("Visuals"),
    World    = Window:AddTab("World"),
    ["UI Settings"] = Window:AddTab("UI Settings"),
}

--// ==================== LEGIT ====================
local MovementBox = Tabs.Legit:AddLeftGroupbox("Movement")

MovementBox:AddToggle("SpeedToggle", {
    Text = "Speed Hack",
    Default = false,
    Tooltip = "Smooth walkspeed modification",
})

MovementBox:AddSlider("SpeedSlider", {
    Text = "WalkSpeed",
    Default = 16,
    Min = 16,
    Max = 60,
    Rounding = 1,
    Compact = false,
})

MovementBox:AddToggle("StaminaToggle", {
    Text = "Infinite Stamina",
    Default = false,
    Tooltip = "Reset local stamina attributes",
})

MovementBox:AddDivider()

MovementBox:AddToggle("JumpToggle", {
    Text = "Jump Power",
    Default = false,
})

MovementBox:AddSlider("JumpSlider", {
    Text = "Jump Power",
    Default = 50,
    Min = 50,
    Max = 200,
    Rounding = 1,
    Compact = false,
})

local WeaponBox = Tabs.Legit:AddRightGroupbox("Weapon")

WeaponBox:AddToggle("RecoilToggle", {
    Text = "Smooth Recoil Control",
    Default = false,
    Tooltip = "Reduce recoil without eliminating",
})

WeaponBox:AddSlider("RecoilSlider", {
    Text = "Reduction %",
    Default = 50,
    Min = 0,
    Max = 100,
    Rounding = 0,
    Compact = false,
})

WeaponBox:AddDivider()

WeaponBox:AddToggle("NoSpreadToggle", {
    Text = "Reduce Spread",
    Default = false,
    Tooltip = "Slight spread reduction (legit)",
})

WeaponBox:AddSlider("SpreadSlider", {
    Text = "Spread Reduction %",
    Default = 40,
    Min = 0,
    Max = 100,
    Rounding = 0,
    Compact = false,
})

--// ==================== VISUALS ====================
local ESPBox = Tabs.Visuals:AddLeftGroupbox("Player ESP")

ESPBox:AddToggle("ESPBoxes",    { Text = "Boxes",       Default = false })
ESPBox:AddToggle("ESPNames",    { Text = "Names",       Default = true  })
ESPBox:AddToggle("ESPDistance", { Text = "Distance",    Default = true  })
ESPBox:AddToggle("ESPHealth",   { Text = "Health Bars", Default = true  })
ESPBox:AddToggle("ESPTracers",  { Text = "Tracers",     Default = false })

ESPBox:AddDivider()

ESPBox:AddSlider("ESPBoxThickness", {
    Text = "Box Thickness",
    Default = 1,
    Min = 1,
    Max = 5,
    Rounding = 1,
    Compact = false,
})

ESPBox:AddColorPicker("ESPBoxColor", {
    Text = "Box Color",
    Default = Color3.fromRGB(255, 255, 255),
})

local ChamsBox = Tabs.Visuals:AddRightGroupbox("Chams")

ChamsBox:AddToggle("ChamsOthers", {
    Text = "Chams on Others",
    Default = false,
})

ChamsBox:AddColorPicker("ChamsVisibleColor", {
    Text = "Visible Color",
    Default = Color3.fromRGB(0, 255, 0),
})

ChamsBox:AddColorPicker("ChamsHiddenColor", {
    Text = "Hidden Color",
    Default = Color3.fromRGB(255, 0, 0),
})

ChamsBox:AddSlider("ChamsOthersTransparency", {
    Text = "Fill Transparency",
    Default = 0.5,
    Min = 0,
    Max = 1,
    Rounding = 2,
    Compact = false,
})

ChamsBox:AddDivider()

ChamsBox:AddToggle("ChamsSelf", {
    Text = "Chams on Self",
    Default = false,
})

ChamsBox:AddColorPicker("ChamsSelfColor", {
    Text = "Self Color",
    Default = Color3.fromRGB(0, 150, 255),
})

ChamsBox:AddSlider("ChamsSelfTransparency", {
    Text = "Self Transparency",
    Default = 0.5,
    Min = 0,
    Max = 1,
    Rounding = 2,
    Compact = false,
})

local HatBox = Tabs.Visuals:AddLeftGroupbox("China Hat")

HatBox:AddToggle("ChinaHatToggle", {
    Text = "China Hat",
    Default = false,
})

HatBox:AddColorPicker("ChinaHatColor", {
    Text = "Hat Color",
    Default = Color3.fromRGB(255, 0, 0),
})

HatBox:AddSlider("ChinaHatRadius", {
    Text = "Radius",
    Default = 2,
    Min = 0.5,
    Max = 6,
    Rounding = 1,
    Compact = false,
})

HatBox:AddSlider("ChinaHatSpeed", {
    Text = "Rotation Speed",
    Default = 1,
    Min = 0,
    Max = 5,
    Rounding = 1,
    Compact = false,
})

HatBox:AddSlider("ChinaHatTransparency", {
    Text = "Transparency",
    Default = 0,
    Min = 0,
    Max = 1,
    Rounding = 2,
    Compact = false,
})

--// ==================== WORLD ====================
local LightBox = Tabs.World:AddLeftGroupbox("Lighting")

LightBox:AddToggle("FullbrightToggle", {
    Text = "Fullbright",
    Default = false,
})

LightBox:AddSlider("BrightnessSlider", {
    Text = "Brightness",
    Default = 2,
    Min = 0,
    Max = 10,
    Rounding = 1,
    Compact = false,
})

LightBox:AddColorPicker("AmbientColor", {
    Text = "Ambient Color",
    Default = Color3.fromRGB(128, 128, 128),
})

LightBox:AddColorPicker("OutdoorAmbientColor", {
    Text = "Outdoor Ambient",
    Default = Color3.fromRGB(128, 128, 128),
})

LightBox:AddDivider()

LightBox:AddToggle("TimeToggle", {
    Text = "Custom Time of Day",
    Default = false,
})

LightBox:AddSlider("TimeSlider", {
    Text = "Clock Time",
    Default = 14,
    Min = 0,
    Max = 24,
    Rounding = 1,
    Compact = false,
})

local FogBox = Tabs.World:AddRightGroupbox("Fog")

FogBox:AddToggle("FogToggle", {
    Text = "Custom Fog",
    Default = false,
})

FogBox:AddSlider("FogEndSlider", {
    Text = "Fog End",
    Default = 1000,
    Min = 0,
    Max = 10000,
    Rounding = 0,
    Compact = false,
})

FogBox:AddColorPicker("FogColorPicker", {
    Text = "Fog Color",
    Default = Color3.fromRGB(192, 192, 192),
})

--// ==================== CUSTOM MODEL ====================
local ModelBox = Tabs.Visuals:AddRightGroupbox("Custom Model")

ModelBox:AddToggle("CustomModelToggle", {
    Text = "Tung Tung Tung Sahura",
    Default = false,
    Tooltip = "Replaces your character model (visual only)",
})

ModelBox:AddButton({
    Text = "Reset Character",
    Func = function()
        LocalPlayer:LoadCharacter()
    end,
})

--// ==================== UI SETTINGS ====================
local MenuGroup = Tabs["UI Settings"]:AddLeftGroupbox("Menu")

MenuGroup:AddButton("Unload", function()
    Library:Unload()
end)

MenuGroup:AddLabel("Menu Toggle Keybind"):AddKeyPicker("MenuKeybind", {
    Default = "RightShift",
    NoUI = true,
    Text = "Menu Toggle",
})

Library.ToggleKeybind = Options.MenuKeybind

MenuGroup:AddDivider()

MenuGroup:AddToggle("WatermarkToggle", {
    Text = "Watermark",
    Default = true,
})

MenuGroup:AddInput("WatermarkText", {
    Text = "Watermark Text",
    Default = "Blood Engine",
    Placeholder = "Text...",
    Numeric = false,
    Finished = false,
})

--// ==================== THEME / SAVE MANAGERS ====================
ThemeManager:SetLibrary(Library)
SaveManager:SetLibrary(Library)

SaveManager:IgnoreThemeSettings()
SaveManager:SetIgnoreIndexes({ "MenuKeybind" })

ThemeManager:SetFolder("BloodEngine")
SaveManager:SetFolder("BloodEngine")

SaveManager:BuildConfigSection(Tabs["UI Settings"])
ThemeManager:ApplyToTab(Tabs["UI Settings"])

-- Автозагрузка последнего конфига
SaveManager:LoadAutoloadConfig()

--// ==================== WATERMARK ====================
local Watermark = Instance.new("TextLabel")
Watermark.Name = "BloodEngine_Watermark"
Watermark.Parent = CoreGui
Watermark.BackgroundTransparency = 0.5
Watermark.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
Watermark.BorderSizePixel = 0
Watermark.Position = UDim2.new(0, 10, 0, 10)
Watermark.Size = UDim2.new(0, 200, 0, 28)
Watermark.Font = Enum.Font.GothamSemibold
Watermark.TextSize = 14
Watermark.TextColor3 = Color3.fromRGB(255, 255, 255)
Watermark.Text = "Blood Engine | Loading..."
Watermark.TextXAlignment = Enum.TextXAlignment.Left
Watermark.Visible = true

local WatermarkPadding = Instance.new("UIPadding")
WatermarkPadding.PaddingLeft = UDim.new(0, 8)
WatermarkPadding.Parent = Watermark

local WatermarkCorner = Instance.new("UICorner")
WatermarkCorner.CornerRadius = UDim.new(0, 4)
WatermarkCorner.Parent = Watermark

Toggles.WatermarkToggle:OnChanged(function(v)
    Watermark.Visible = v
end)

Options.WatermarkText:OnChanged(function(v)
    Watermark.Text = tostring(v) .. " | " .. os.date("%H:%M:%S")
end)

task.spawn(function()
    while Watermark and Watermark.Parent do
        Watermark.Text = tostring(Options.WatermarkText.Value or "Blood Engine") .. " | " .. os.date("%H:%M:%S")
        task.wait(1)
    end
end)

--// ==================== STATE ====================
local State = {
    TargetSpeed = 16,
    TargetJump = 50,
    RecoilReduction = 0.5,
    SpreadReduction = 0.4,
    ChamsVisibleColor = Color3.fromRGB(0, 255, 0),
    ChamsHiddenColor = Color3.fromRGB(255, 0, 0),
    ChamsSelfColor = Color3.fromRGB(0, 150, 255),
    ChamsSelfTransparency = 0.5,
    ChamsOthersTransparency = 0.5,
    ChinaHatColor = Color3.fromRGB(255, 0, 0),
    ChinaHatRadius = 2,
    ChinaHatSpeed = 1,
    ChinaHatTransparency = 0,
    ESPBoxColor = Color3.fromRGB(255, 255, 255),
    ESPBoxThickness = 1,
}

--// ==================== ESP ====================
local ESPObjects = {}
local ActiveChams = {}

local function CreateESP(player)
    if player == LocalPlayer then return end

    -- очистка
    if ESPObjects[player] then
        for _, obj in pairs(ESPObjects[player]) do
            pcall(function() obj:Remove() end)
        end
    end

    local esp = {}
    local box = Drawing.new("Quad")
    box.Visible = false
    box.Thickness = State.ESPBoxThickness
    box.Color = State.ESPBoxColor
    box.Filled = false
    box.Transparency = 1
    esp.Box = box

    local name = Drawing.new("Text")
    name.Visible = false
    name.Center = true
    name.Outline = true
    name.Font = 2
    name.Size = 13
    name.Color = Color3.fromRGB(255, 255, 255)
    name.Transparency = 1
    esp.Name = name

    local dist = Drawing.new("Text")
    dist.Visible = false
    dist.Center = true
    dist.Outline = true
    dist.Font = 2
    dist.Size = 12
    dist.Color = Color3.fromRGB(200, 200, 200)
    dist.Transparency = 1
    esp.Distance = dist

    local healthBG = Drawing.new("Quad")
    healthBG.Visible = false
    healthBG.Thickness = 1
    healthBG.Color = Color3.fromRGB(0, 0, 0)
    healthBG.Filled = true
    healthBG.Transparency = 1
    esp.HealthBG = healthBG

    local health = Drawing.new("Quad")
    health.Visible = false
    health.Thickness = 1
    health.Color = Color3.fromRGB(0, 255, 0)
    health.Filled = true
    health.Transparency = 1
    esp.Health = health

    local tracer = Drawing.new("Line")
    tracer.Visible = false
    tracer.Thickness = 1
    tracer.Color = State.ESPBoxColor
    tracer.Transparency = 1
    esp.Tracer = tracer

    ESPObjects[player] = esp
end

local function HideESP(esp)
    for _, obj in pairs(esp) do
        pcall(function() obj.Visible = false end)
    end
end

local function UpdateESP()
    for player, esp in pairs(ESPObjects) do
        local char = player.Character
        local root = char and char:FindFirstChild("HumanoidRootPart")
        local head = char and char:FindFirstChild("Head")
        local hum = char and char:FindFirstChildOfClass("Humanoid")

        if not (root and head and hum) or hum.Health <= 0 then
            HideESP(esp)
            continue
        end

        local headPos, onScreen = Camera:WorldToViewportPoint(head.Position + Vector3.new(0, 0.75, 0))
        local rootPos = Camera:WorldToViewportPoint(root.Position - Vector3.new(0, 3, 0))

        if not onScreen then
            HideESP(esp)
            continue
        end

        local top = headPos.Y
        local bottom = rootPos.Y
        local height = math.abs(top - bottom)
        local width = height * 0.55
        local posX = headPos.X

        -- Box
        esp.Box.Visible = Toggles.ESPBoxes.Value
        if esp.Box.Visible then
            esp.Box.Thickness = State.ESPBoxThickness
            esp.Box.Color = State.ESPBoxColor
            esp.Box.PointA = Vector2.new(posX - width / 2, top)
            esp.Box.PointB = Vector2.new(posX + width / 2, top)
            esp.Box.PointC = Vector2.new(posX + width / 2, bottom)
            esp.Box.PointD = Vector2.new(posX - width / 2, bottom)
        end

        -- Name
        esp.Name.Visible = Toggles.ESPNames.Value
        if esp.Name.Visible then
            esp.Name.Position = Vector2.new(posX, top - 18)
            esp.Name.Text = player.Name
        end

        -- Distance
        esp.Distance.Visible = Toggles.ESPDistance.Value
        if esp.Distance.Visible then
            local d = (Camera.CFrame.Position - root.Position).Magnitude
            esp.Distance.Position = Vector2.new(posX, bottom + 2)
            esp.Distance.Text = string.format("[%d]", math.floor(d))
        end

        -- Health
        local showHealth = Toggles.ESPHealth.Value
        esp.HealthBG.Visible = showHealth
        esp.Health.Visible = showHealth
        if showHealth then
            local pct = math.clamp(hum.Health / hum.MaxHealth, 0, 1)
            local x1 = posX + width / 2 + 4
            local x2 = posX + width / 2 + 9
            esp.HealthBG.PointA = Vector2.new(x1, bottom)
            esp.HealthBG.PointB = Vector2.new(x2, bottom)
            esp.HealthBG.PointC = Vector2.new(x2, top)
            esp.HealthBG.PointD = Vector2.new(x1, top)

            local hTop = bottom - height * pct
            esp.Health.PointA = Vector2.new(x1, hTop)
            esp.Health.PointB = Vector2.new(x2, hTop)
            esp.Health.PointC = Vector2.new(x2, bottom)
            esp.Health.PointD = Vector2.new(x1, bottom)

            esp.Health.Color = Color3.fromRGB(255 * (1 - pct), 255 * pct, 0)
        end

        -- Tracer
        esp.Tracer.Visible = Toggles.ESPTracers.Value
        if esp.Tracer.Visible then
            esp.Tracer.From = Vector2.new(Camera.ViewportSize.X / 2, Camera.ViewportSize.Y)
            esp.Tracer.To = Vector2.new(posX, bottom)
            esp.Tracer.Color = State.ESPBoxColor
        end
    end
end

-- Регистрация игроков
for _, p in pairs(Players:GetPlayers()) do
    if p ~= LocalPlayer then CreateESP(p) end
end

Players.PlayerAdded:Connect(function(p)
    if p ~= LocalPlayer then CreateESP(p) end
end)

Players.PlayerRemoving:Connect(function(p)
    if ESPObjects[p] then
        for _, obj in pairs(ESPObjects[p]) do
            pcall(function() obj:Remove() end)
        end
        ESPObjects[p] = nil
    end
    if ActiveChams[p] then
        ActiveChams[p]:Destroy()
        ActiveChams[p] = nil
    end
end)

--// ==================== CHAMS ====================
local function ApplyChams(player, isSelf)
    if ActiveChams[player] then
        ActiveChams[player]:Destroy()
        ActiveChams[player] = nil
    end
    if not player.Character then return end

    local hl = Instance.new("Highlight")
    hl.Name = "BE_Chams"
    hl.Adornee = player.Character

    if isSelf then
        hl.FillColor = State.ChamsSelfColor
        hl.FillTransparency = State.ChamsSelfTransparency
        hl.OutlineColor = State.ChamsSelfColor
        hl.OutlineTransparency = 0
        hl.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
    else
        hl.FillColor = State.ChamsVisibleColor
        hl.FillTransparency = State.ChamsOthersTransparency
        hl.OutlineColor = State.ChamsHiddenColor
        hl.OutlineTransparency = 0
        hl.DepthMode = Enum.HighlightDepthMode.Occluded
    end

    hl.Parent = player.Character
    ActiveChams[player] = hl
end

local function RemoveChams(player)
    if ActiveChams[player] then
        ActiveChams[player]:Destroy()
        ActiveChams[player] = nil
    end
end

--// ==================== CHINA HAT ====================
local ChinaHat = nil
local HatGyro = nil

local function DestroyChinaHat()
    if ChinaHat then ChinaHat:Destroy() ChinaHat = nil end
    HatGyro = nil
end

local function CreateChinaHat()
    DestroyChinaHat()
    local char = LocalPlayer.Character
    if not char then return end
    local head = char:FindFirstChild("Head")
    if not head then return end

    local cone = Instance.new("Part")
    cone.Name = "BE_ChinaHat"
    cone.Shape = Enum.PartType.Cone
    cone.Size = Vector3.new(State.ChinaHatRadius * 2, State.ChinaHatRadius * 2, State.ChinaHatRadius * 2)
    cone.Color = State.ChinaHatColor
    cone.Material = Enum.Material.Neon
    cone.Transparency = State.ChinaHatTransparency
    cone.CanCollide = false
    cone.CanQuery = false
    cone.CanTouch = false
    cone.Massless = true
    cone.Anchored = false
    cone.CFrame = head.CFrame * CFrame.new(0, head.Size.Y / 2 + State.ChinaHatRadius, 0)
    cone.Parent = char

    local att = Instance.new("Attachment")
    att.Parent = cone

    local gyro = Instance.new("BodyAngularVelocity")
    gyro.AngularVelocity = Vector3.new(0, State.ChinaHatSpeed * 5, 0)
    gyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
    gyro.P = 1000
    gyro.Parent = cone

    local weld = Instance.new("WeldConstraint")
    weld.Part0 = cone
    weld.Part1 = head
    weld.Parent = cone

    ChinaHat = cone
    HatGyro = gyro
end

--// ==================== CHARACTER HANDLERS ====================
local function OnCharacterAdded(char)
    task.wait(0.25)
    if Toggles.ChamsSelf.Value then ApplyChams(LocalPlayer, true) end
    if Toggles.ChamsOthers.Value then
        for _, p in pairs(Players:GetPlayers()) do
            if p ~= LocalPlayer then ApplyChams(p, false) end
        end
    end
    if Toggles.ChinaHatToggle.Value then CreateChinaHat() end
end

LocalPlayer.CharacterAdded:Connect(OnCharacterAdded)
if LocalPlayer.Character then OnCharacterAdded(LocalPlayer.Character) end

--// ==================== MOVEMENT ====================
RunService.Heartbeat:Connect(function(dt)
    local char = LocalPlayer.Character
    if not char then return end
    local hum = char:FindFirstChildOfClass("Humanoid")
    if not hum then return end

    if Toggles.SpeedToggle.Value then
        local target = Options.SpeedSlider.Value
        hum.WalkSpeed = hum.WalkSpeed + (target - hum.WalkSpeed) * math.min(dt * 8, 1)
    end

    if Toggles.JumpToggle.Value then
        hum.UseJumpPower = true
        hum.JumpPower = Options.JumpSlider.Value
    end

    if Toggles.StaminaToggle.Value then
        for _, attr in ipairs({"Stamina", "Fatigue", "Energy", "Sprint"}) do
            pcall(function()
                if hum:GetAttribute(attr) then hum:SetAttribute(attr, 100) end
            end)
        end
    end
end)

--// ==================== WORLD ====================
local originalLighting = {
    Ambient = Lighting.Ambient,
    OutdoorAmbient = Lighting.OutdoorAmbient,
    Brightness = Lighting.Brightness,
    FogEnd = Lighting.FogEnd,
    FogColor = Lighting.FogColor,
    ClockTime = Lighting.ClockTime,
    GlobalShadows = Lighting.GlobalShadows,
}

local function UpdateWorld()
    if Toggles.Fullbright.Value then
        Lighting.Brightness = Options.BrightnessSlider.Value
        Lighting.GlobalShadows = false
        Lighting.FogEnd = 1e6
        Lighting.EnvironmentDiffuseScale = 1
        Lighting.EnvironmentSpecularScale = 1
    else
        Lighting.Brightness = originalLighting.Brightness
        Lighting.GlobalShadows = originalLighting.GlobalShadows
    end

    Lighting.Ambient = Options.AmbientColor.Value
    Lighting.OutdoorAmbient = Options.OutdoorAmbientColor.Value

    if Toggles.FogToggle.Value then
        Lighting.FogEnd = Options.FogEndSlider.Value
        Lighting.FogColor = Options.FogColorPicker.Value
    else
        Lighting.FogEnd = originalLighting.FogEnd
        Lighting.FogColor = originalLighting.FogColor
    end

    if Toggles.TimeToggle.Value then
        Lighting.ClockTime = Options.TimeSlider.Value
    end
end

--// ==================== UI CALLBACKS ====================
Options.SpeedSlider:OnChanged(function(v) State.TargetSpeed = v end)
Options.JumpSlider:OnChanged(function(v) State.TargetJump = v end)
Options.RecoilSlider:OnChanged(function(v) State.RecoilReduction = v / 100 end)
Options.SpreadSlider:OnChanged(function(v) State.SpreadReduction = v / 100 end)

Options.ESPBoxThickness:OnChanged(function(v) State.ESPBoxThickness = v end)
Options.ESPBoxColor:OnChanged(function(c) State.ESPBoxColor = c end)

-- Chams callbacks
Toggles.ChamsOthers:OnChanged(function(v)
    for _, p in pairs(Players:GetPlayers()) do
        if p ~= LocalPlayer then
            if v then ApplyChams(p, false) else RemoveChams(p) end
        end
    end
end)

Options.ChamsVisibleColor:OnChanged(function(c)
    State.ChamsVisibleColor = c
    for _, p in pairs(Players:GetPlayers()) do
        if p ~= LocalPlayer and ActiveChams[p] then
            ActiveChams[p].FillColor = c
        end
    end
end)

Options.ChamsHiddenColor:OnChanged(function(c)
    State.ChamsHiddenColor = c
    for _, p in pairs(Players:GetPlayers()) do
        if p ~= LocalPlayer and ActiveChams[p] then
            ActiveChams[p].OutlineColor = c
        end
    end
end)

Options.ChamsOthersTransparency:OnChanged(function(v)
    State.ChamsOthersTransparency = v
    for _, p in pairs(Players:GetPlayers()) do
        if p ~= LocalPlayer and ActiveChams[p] then
            ActiveChams[p].FillTransparency = v
        end
    end
end)

Toggles.ChamsSelf:OnChanged(function(v)
    if v then ApplyChams(LocalPlayer, true) else RemoveChams(LocalPlayer) end
end)

Options.ChamsSelfColor:OnChanged(function(c)
    State.ChamsSelfColor = c
    if ActiveChams[LocalPlayer] then
        ActiveChams[LocalPlayer].FillColor = c
        ActiveChams[LocalPlayer].OutlineColor = c
    end
end)

Options.ChamsSelfTransparency:OnChanged(function(v)
    State.ChamsSelfTransparency = v
    if ActiveChams[LocalPlayer] then
        ActiveChams[LocalPlayer].FillTransparency = v
    end
end)

-- China hat callbacks
Toggles.ChinaHatToggle:OnChanged(function(v)
    if v then CreateChinaHat() else DestroyChinaHat() end
end)

Options.ChinaHatColor:OnChanged(function(c)
    State.ChinaHatColor = c
    if ChinaHat then ChinaHat.Color = c end
end)

Options.ChinaHatRadius:OnChanged(function(v)
    State.ChinaHatRadius = v
    if ChinaHat then ChinaHat.Size = Vector3.new(v * 2, v * 2, v * 2) end
end)

Options.ChinaHatSpeed:OnChanged(function(v)
    State.ChinaHatSpeed = v
    if HatGyro then HatGyro.AngularVelocity = Vector3.new(0, v * 5, 0) end
end)

Options.ChinaHatTransparency:OnChanged(function(v)
    State.ChinaHatTransparency = v
    if ChinaHat then ChinaHat.Transparency = v end
end)

-- World callbacks
Toggles.FullbrightToggle:OnChanged(UpdateWorld)
Options.BrightnessSlider:OnChanged(UpdateWorld)
Options.AmbientColor:OnChanged(UpdateWorld)
Options.OutdoorAmbientColor:OnChanged(UpdateWorld)
Toggles.FogToggle:OnChanged(UpdateWorld)
Options.FogEndSlider:OnChanged(UpdateWorld)
Options.FogColorPicker:OnChanged(UpdateWorld)
Toggles.TimeToggle:OnChanged(UpdateWorld)
Options.TimeSlider:OnChanged(UpdateWorld)

--// ==================== RECOIL HOOK ====================
-- Hook into camera recoil (many Roblox FPS games modify Camera.CFrame)
local LastCameraCFrame = Camera.CFrame
RunService.RenderStepped:Connect(function()
    if Toggles.RecoilToggle.Value then
        local current = Camera.CFrame
        -- Сглаживание резких скачков камеры (отдача)
        local delta = (current.Position - LastCameraCFrame.Position).Magnitude
        if delta > 0.05 then
            local smoothed = LastCameraCFrame:Lerp(current, 1 - State.RecoilReduction)
            Camera.CFrame = smoothed
        end
        LastCameraCFrame = Camera.CFrame
    else
        LastCameraCFrame = Camera.CFrame
    end
end)

--// ==================== MAIN LOOP ====================
RunService.RenderStepped:Connect(UpdateESP)

--// ==================== CLEANUP ====================
Library:OnUnload(function()
    DestroyChinaHat()
    for _, esp in pairs(ESPObjects) do
        for _, obj in pairs(esp) do
            pcall(function() obj:Remove() end)
        end
    end
    for _, hl in pairs(ActiveChams) do
        pcall(function() hl:Destroy() end)
    end
    if Watermark then Watermark:Destroy() end

    -- Restore lighting
    for k, v in pairs(originalLighting) do
        pcall(function() Lighting[k] = v end)
    end
end)

Library:Notify("Blood Engine loaded", 3)