--[[
    efg2g loader  +  Junkie Key System
    ------------------------------------------------------------------
    Flow:
      1. Kunin ang supported games list  (/scripts/supported.lua)
      2. Key system (Junkie SDK)  ->  saved key / keyless / key UI
      3. getgenv().SCRIPT_KEY = validated key
      4. I-load ang game script (Junkie CDN URL  o  /games/<file>.lua)

    Junkie docs: https://docs.jnkie.com/roblox-sdk/external-loader
]]

repeat task.wait() until game:IsLoaded()

local Players     = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer

-- =====================================================================
--  CONFIG  (ito lang ang kailangan mong i-edit)
-- =====================================================================
local BRAND  = "efg2g"
local DOMAIN = "efg2g.pages.dev"

local SUPPORTED_URL  = "https://" .. DOMAIN .. "/scripts/supported.lua"
local GAMES_BASE_URL = "https://" .. DOMAIN .. "/games/"

local JUNKIE = {
    ENABLED    = true,                               -- false = walang key system (dev/testing lang)
    SDK_URL    = "https://jnkie.com/sdk/library.lua",

    SERVICE    = "efg2g-free",                            -- Dashboard -> Services   (service name)
    IDENTIFIER = "1136363",                     -- Dashboard -> your user ID (string, e.g. "12345")
    PROVIDER   = "Free",                             -- Dashboard -> Providers  (provider name)

    SAVE_KEY   = true,                               -- i-save ang valid key sa file para hindi na mag-type ulit
    KEY_FOLDER = "efg2g",
    KEY_FILE   = "efg2g/key.txt",

    -- Kapag TRUE, susubukan muna ang "KEYLESS" bago ipakita ang UI.
    -- Dahil dito gumagana ang "Keyless mode" / "Keyless weekdays" toggle
    -- sa dashboard nang hindi na kailangang i-redeploy ang loader.
    KEYLESS_PROBE = true,
}
-- =====================================================================

local function kick(msg)
    pcall(function()
        LocalPlayer:Kick("[" .. BRAND .. "] " .. msg)
    end)
end

local function notify(title, text, duration)
    pcall(function()
        game:GetService("StarterGui"):SetCore("SendNotification", {
            Title    = title,
            Text     = text,
            Duration = duration or 4,
        })
    end)
end

local function trim(s)
    return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", ""))
end

local function httpGet(url)
    -- Try request() first (available sa karamihan ng modern executors) para makuha ang status code
    if type(request) == "function" then
        local ok, resp = pcall(function()
            return request({
                Url = url,
                Method = "GET",
                Headers = {
                    ["Accept"] = "text/plain,application/octet-stream,*/*",
                },
            })
        end)
        if ok and type(resp) == "table" then
            local code = tonumber(resp.StatusCode) or 0
            local body = resp.Body or ""
            if code >= 200 and code < 300 and #body > 0 then
                return body
            end
            return nil, "HTTP " .. tostring(code)
        end
        -- Fall through sa game:HttpGet kung nag-fail ang request()
    end

    local ok, res = pcall(function()
        return game:HttpGet(url, true)
    end)
    if not ok then
        return nil, tostring(res)
    end
    return res
end

-- =====================================================================
--  1) SUPPORTED GAMES
-- =====================================================================
local okList, SUPPORTED_GAMES = pcall(function()
    local src = game:HttpGet(SUPPORTED_URL, true)
    return loadstring(src)()
end)

if not okList or type(SUPPORTED_GAMES) ~= "table" then
    kick("Failed to load game list.")
    return
end

local entry = SUPPORTED_GAMES[game.PlaceId]

if not entry then
    kick("does not support this game.\nPlaceId: " .. tostring(game.PlaceId))
    return
end

-- entry can be:  "142823291.lua"  (file sa /games/)   o   "https://..." (full URL, e.g. Junkie CDN)
local scriptUrl
if type(entry) == "table" then
    scriptUrl = entry.url or entry.file
else
    scriptUrl = entry
end
if type(scriptUrl) ~= "string" or #scriptUrl == 0 then
    kick("Invalid entry in game list for PlaceId " .. tostring(game.PlaceId))
    return
end
if not scriptUrl:match("^https?://") then
    scriptUrl = GAMES_BASE_URL .. scriptUrl
end

-- =====================================================================
--  2) KEY SYSTEM  (Junkie)
-- =====================================================================
local ERROR_TEXT = {
    KEY_INVALID       = "Invalid key. Please check and try again.",
    KEY_EXPIRED       = "Your key has expired. Click 'Get Key' for a new one.",
    HWID_BANNED       = "You are HWID banned from this script.",
    KEY_INVALIDATED   = "This key has been disabled.",
    ALREADY_USED      = "This one-time key was already used.",
    HWID_MISMATCH     = "This key is bound to another device (HWID limit reached).",
    SERVICE_NOT_FOUND = "Service not found. (Loader config error - contact the owner.)",
    SERVICE_MISMATCH  = "This key is for a different script.",
    PREMIUM_REQUIRED  = "A premium key is required for this script.",
    RATE_LIMITED      = "Rate limited. Please wait ~5 minutes and try again.",
    ERROR             = "Network error. Please try again.",
}

local function describe(code)
    code = tostring(code or "ERROR")
    if ERROR_TEXT[code] then
        return ERROR_TEXT[code]
    end
    if code:match("^http %d+") then
        return "Server error (" .. code .. "). Try again in a moment."
    end
    return code
end

local function loadJunkie()
    local ok, lib = pcall(function()
        return loadstring(game:HttpGet(JUNKIE.SDK_URL, true))()
    end)
    if not ok or type(lib) ~= "table" then
        return nil, tostring(lib)
    end
    lib.service    = JUNKIE.SERVICE
    lib.identifier = tostring(JUNKIE.IDENTIFIER)
    lib.provider   = JUNKIE.PROVIDER
    return lib
end

-- returns: valid(boolean), code(string)   code = "KEY_VALID" | "KEYLESS" | <error code>
local function checkKey(Junkie, key)
    local ok, res = pcall(Junkie.check_key, key)
    if not ok or type(res) ~= "table" then
        return false, "ERROR"
    end
    if res.valid or res.success then
        return true, res.message or "KEY_VALID"
    end
    return false, res.error or res.message or "KEY_INVALID"
end

-- returns: link(string|nil), err(string|nil)
local function getKeyLink(Junkie)
    local ok, link, err = pcall(Junkie.get_key_link)
    if not ok then
        return nil, "ERROR"
    end
    if type(link) == "string" and #link > 0 then
        return link, nil
    end
    return nil, tostring(err or "ERROR")
end

-- ---------- saved key (file) ----------
local function fsAvailable()
    return JUNKIE.SAVE_KEY
        and type(readfile) == "function"
        and type(writefile) == "function"
        and type(isfile) == "function"
end

local function loadSavedKey()
    if not fsAvailable() then return nil end
    local ok, key = pcall(function()
        if isfile(JUNKIE.KEY_FILE) then
            return readfile(JUNKIE.KEY_FILE)
        end
        return nil
    end)
    if ok and type(key) == "string" then
        key = trim(key)
        if #key > 0 then return key end
    end
    return nil
end

local function saveKey(key)
    if not fsAvailable() then return end
    pcall(function()
        if type(makefolder) == "function" and type(isfolder) == "function" then
            if not isfolder(JUNKIE.KEY_FOLDER) then
                makefolder(JUNKIE.KEY_FOLDER)
            end
        end
        writefile(JUNKIE.KEY_FILE, key)
    end)
end

local function clearSavedKey()
    if not fsAvailable() then return end
    pcall(function()
        if isfile(JUNKIE.KEY_FILE) then
            if type(delfile) == "function" then
                delfile(JUNKIE.KEY_FILE)
            else
                writefile(JUNKIE.KEY_FILE, "")
            end
        end
    end)
end

local function copyToClipboard(text)
    local fn = setclipboard or toclipboard or set_clipboard
        or (Clipboard and Clipboard.set)
    if type(fn) ~= "function" then return false end
    return pcall(fn, text)
end

-- ---------- Key UI ----------
local THEME = {
    Background = Color3.fromRGB(12, 12, 15),
    Panel      = Color3.fromRGB(21, 21, 27),
    Stroke     = Color3.fromRGB(42, 42, 54),
    Accent     = Color3.fromRGB(0, 212, 255),
    AccentText = Color3.fromRGB(5, 5, 8),
    Text       = Color3.fromRGB(240, 240, 245),
    Muted      = Color3.fromRGB(140, 140, 158),
    Success    = Color3.fromRGB(80, 220, 140),
    Error      = Color3.fromRGB(255, 92, 92),
    Warning    = Color3.fromRGB(255, 190, 70),
}

local function new(class, props, parent)
    local inst = Instance.new(class)
    for k, v in pairs(props or {}) do
        inst[k] = v
    end
    if parent then
        inst.Parent = parent
    end
    return inst
end

local function getGuiParent(gui)
    if type(protect_gui) == "function" then
        pcall(protect_gui, gui)
    end
    if type(gethui) == "function" then
        local ok, hui = pcall(gethui)
        if ok and hui then return hui end
    end
    local okCore = pcall(function()
        return game:GetService("CoreGui"):GetChildren()
    end)
    if okCore then
        return game:GetService("CoreGui")
    end
    return LocalPlayer:WaitForChild("PlayerGui")
end

local function makeDraggable(frame, handle)
    local UIS = game:GetService("UserInputService")
    local dragging, dragInput, dragStart, startPos

    handle.InputBegan:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseButton1
            or input.UserInputType == Enum.UserInputType.Touch then
            dragging  = true
            dragStart = input.Position
            startPos  = frame.Position
            input.Changed:Connect(function()
                if input.UserInputState == Enum.UserInputState.End then
                    dragging = false
                end
            end)
        end
    end)

    handle.InputChanged:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseMovement
            or input.UserInputType == Enum.UserInputType.Touch then
            dragInput = input
        end
    end)

    UIS.InputChanged:Connect(function(input)
        if dragging and input == dragInput then
            local delta = input.Position - dragStart
            frame.Position = UDim2.new(
                startPos.X.Scale, startPos.X.Offset + delta.X,
                startPos.Y.Scale, startPos.Y.Offset + delta.Y
            )
        end
    end)
end

local function createKeyUI(handlers)
    local gui = new("ScreenGui", {
        Name           = BRAND .. "_KeySystem",
        ResetOnSpawn   = false,
        ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
        DisplayOrder   = 999,
    })
    gui.Parent = getGuiParent(gui)

    local window = new("Frame", {
        Name             = "Window",
        AnchorPoint      = Vector2.new(0.5, 0.5),
        Position         = UDim2.new(0.5, 0, 0.5, 0),
        Size             = UDim2.new(0, 380, 0, 262),
        BackgroundColor3 = THEME.Background,
        BorderSizePixel  = 0,
    }, gui)
    new("UICorner", { CornerRadius = UDim.new(0, 12) }, window)
    new("UIStroke", { Color = THEME.Stroke, Thickness = 1 }, window)

    -- header
    local header = new("Frame", {
        Name                   = "Header",
        Size                   = UDim2.new(1, 0, 0, 52),
        BackgroundTransparency = 1,
    }, window)

    new("TextLabel", {
        Name                   = "Title",
        Position               = UDim2.new(0, 16, 0, 10),
        Size                   = UDim2.new(1, -70, 0, 20),
        BackgroundTransparency = 1,
        Text                   = BRAND,
        TextColor3             = THEME.Text,
        Font                   = Enum.Font.GothamBold,
        TextSize               = 17,
        TextXAlignment         = Enum.TextXAlignment.Left,
    }, header)

    new("TextLabel", {
        Name                   = "Subtitle",
        Position               = UDim2.new(0, 16, 0, 30),
        Size                   = UDim2.new(1, -70, 0, 16),
        BackgroundTransparency = 1,
        Text                   = "Key System  •  complete the checkpoint to get your key",
        TextColor3             = THEME.Muted,
        Font                   = Enum.Font.Gotham,
        TextSize               = 11,
        TextXAlignment         = Enum.TextXAlignment.Left,
        TextTruncate           = Enum.TextTruncate.AtEnd,
    }, header)

    local closeBtn = new("TextButton", {
        Name                   = "Close",
        AnchorPoint            = Vector2.new(1, 0),
        Position               = UDim2.new(1, -12, 0, 12),
        Size                   = UDim2.new(0, 28, 0, 28),
        BackgroundColor3       = THEME.Panel,
        Text                   = "×",
        TextColor3             = THEME.Muted,
        Font                   = Enum.Font.GothamBold,
        TextSize               = 18,
        AutoButtonColor        = false,
    }, header)
    new("UICorner", { CornerRadius = UDim.new(0, 8) }, closeBtn)

    -- key input
    local keyBox = new("TextBox", {
        Name                   = "KeyInput",
        Position               = UDim2.new(0, 16, 0, 62),
        Size                   = UDim2.new(1, -32, 0, 38),
        BackgroundColor3       = THEME.Panel,
        BorderSizePixel        = 0,
        Text                   = "",
        PlaceholderText        = "Paste your key here...",
        PlaceholderColor3      = THEME.Muted,
        TextColor3             = THEME.Text,
        Font                   = Enum.Font.Gotham,
        TextSize               = 13,
        ClearTextOnFocus       = false,
        TextXAlignment         = Enum.TextXAlignment.Left,
    }, window)
    new("UICorner", { CornerRadius = UDim.new(0, 8) }, keyBox)
    new("UIStroke", { Color = THEME.Stroke, Thickness = 1 }, keyBox)
    new("UIPadding", { PaddingLeft = UDim.new(0, 12), PaddingRight = UDim.new(0, 12) }, keyBox)

    -- buttons
    local getKeyBtn = new("TextButton", {
        Name             = "GetKey",
        Position         = UDim2.new(0, 16, 0, 110),
        Size             = UDim2.new(0.5, -20, 0, 36),
        BackgroundColor3 = THEME.Accent,
        BorderSizePixel  = 0,
        Text             = "Get Key",
        TextColor3       = THEME.AccentText,
        Font             = Enum.Font.GothamBold,
        TextSize         = 13,
        AutoButtonColor  = false,
    }, window)
    new("UICorner", { CornerRadius = UDim.new(0, 8) }, getKeyBtn)

    local checkBtn = new("TextButton", {
        Name             = "CheckKey",
        AnchorPoint      = Vector2.new(1, 0),
        Position         = UDim2.new(1, -16, 0, 110),
        Size             = UDim2.new(0.5, -20, 0, 36),
        BackgroundColor3 = THEME.Panel,
        BorderSizePixel  = 0,
        Text             = "Check Key",
        TextColor3       = THEME.Text,
        Font             = Enum.Font.GothamBold,
        TextSize         = 13,
        AutoButtonColor  = false,
    }, window)
    new("UICorner", { CornerRadius = UDim.new(0, 8) }, checkBtn)
    new("UIStroke", { Color = THEME.Stroke, Thickness = 1 }, checkBtn)

    -- link box (read-only; para makopya sa mobile kung walang setclipboard)
    local linkBox = new("TextBox", {
        Name                   = "KeyLink",
        Position               = UDim2.new(0, 16, 0, 156),
        Size                   = UDim2.new(1, -32, 0, 30),
        BackgroundColor3       = THEME.Panel,
        BorderSizePixel        = 0,
        Text                   = "",
        TextColor3             = THEME.Accent,
        Font                   = Enum.Font.Code,
        TextSize               = 11,
        ClearTextOnFocus       = false,
        TextEditable           = false,
        TextXAlignment         = Enum.TextXAlignment.Left,
        Visible                = false,
    }, window)
    new("UICorner", { CornerRadius = UDim.new(0, 8) }, linkBox)
    new("UIPadding", { PaddingLeft = UDim.new(0, 10), PaddingRight = UDim.new(0, 10) }, linkBox)

    -- status
    local status = new("TextLabel", {
        Name                   = "Status",
        Position               = UDim2.new(0, 16, 0, 192),
        Size                   = UDim2.new(1, -32, 0, 40),
        BackgroundTransparency = 1,
        Text                   = "Click 'Get Key' to receive your key link, then paste the key above.",
        TextColor3             = THEME.Muted,
        Font                   = Enum.Font.Gotham,
        TextSize               = 12,
        TextWrapped            = true,
        TextXAlignment         = Enum.TextXAlignment.Left,
        TextYAlignment         = Enum.TextYAlignment.Top,
    }, window)

    new("TextLabel", {
        Name                   = "Footer",
        Position               = UDim2.new(0, 16, 1, -22),
        Size                   = UDim2.new(1, -32, 0, 14),
        BackgroundTransparency = 1,
        Text                   = BRAND .. "  •  secured by Junkie",
        TextColor3             = THEME.Stroke,
        Font                   = Enum.Font.Gotham,
        TextSize               = 10,
        TextXAlignment         = Enum.TextXAlignment.Right,
    }, window)

    makeDraggable(window, header)

    -- hover effects
    local function hover(btn, normal, hovered)
        btn.MouseEnter:Connect(function() btn.BackgroundColor3 = hovered end)
        btn.MouseLeave:Connect(function() btn.BackgroundColor3 = normal end)
    end
    hover(getKeyBtn, THEME.Accent, Color3.fromRGB(80, 226, 255))
    hover(checkBtn,  THEME.Panel,  Color3.fromRGB(32, 32, 41))
    hover(closeBtn,  THEME.Panel,  Color3.fromRGB(60, 30, 34))

    -- wiring
    getKeyBtn.MouseButton1Click:Connect(function()
        handlers.onGetKey()
    end)
    checkBtn.MouseButton1Click:Connect(function()
        handlers.onCheck(keyBox.Text)
    end)
    keyBox.FocusLost:Connect(function(enterPressed)
        if enterPressed then
            handlers.onCheck(keyBox.Text)
        end
    end)
    closeBtn.MouseButton1Click:Connect(function()
        handlers.onClose()
    end)

    local ui = {}

    function ui:SetStatus(text, kind)
        status.Text = text
        if kind == "ok" then
            status.TextColor3 = THEME.Success
        elseif kind == "err" then
            status.TextColor3 = THEME.Error
        elseif kind == "warn" then
            status.TextColor3 = THEME.Warning
        else
            status.TextColor3 = THEME.Muted
        end
    end

    function ui:ShowLink(link)
        linkBox.Text    = link
        linkBox.Visible = true
        getKeyBtn.Text  = "Copy Link"
    end

    function ui:SetBusy(busy)
        getKeyBtn.Active = not busy
        checkBtn.Active  = not busy
        checkBtn.Text    = busy and "Checking..." or "Check Key"
    end

    function ui:Destroy()
        pcall(function() gui:Destroy() end)
    end

    return ui
end

-- returns validated key (string) or nil kapag hindi nag-proceed
local function runKeySystem()
    local Junkie = loadJunkie()
    if not Junkie then
        kick("Failed to load key system. Please re-execute.")
        return nil
    end

    -- (a) silent checks -> skip UI kung may valid na
    --     1. getgenv().SCRIPT_KEY na pre-set (e.g. galing sa "ready-to-copy loadstring" ng Junkie flow)
    --     2. saved key sa file
    --     3. "KEYLESS" probe (kung walang 1 at 2)
    local candidates = {}
    local preset = getgenv().SCRIPT_KEY
    if type(preset) == "string" and #trim(preset) > 0 then
        table.insert(candidates, { key = trim(preset), source = "preset" })
    end
    local saved = loadSavedKey()
    if saved and saved ~= (candidates[1] and candidates[1].key) then
        table.insert(candidates, { key = saved, source = "saved" })
    end
    if #candidates == 0 and JUNKIE.KEYLESS_PROBE then
        table.insert(candidates, { key = "KEYLESS", source = "probe" })
    end

    for _, c in ipairs(candidates) do
        local valid, code = checkKey(Junkie, c.key)
        if valid then
            if c.source == "preset" and code ~= "KEYLESS" then
                saveKey(c.key)
            end
            return c.key, code
        end
        if code == "HWID_BANNED" then
            kick(ERROR_TEXT.HWID_BANNED)
            return nil
        end
        if c.source == "saved" and (code == "KEY_INVALID" or code == "KEY_EXPIRED"
            or code == "KEY_INVALIDATED" or code == "ALREADY_USED"
            or code == "SERVICE_MISMATCH") then
            clearSavedKey()
        end
    end

    -- (b) UI
    local result     = nil   -- string = key, false = closed
    local resultCode = nil
    local busy       = false
    local cachedLink = nil
    local ui

    ui = createKeyUI({
        onGetKey = function()
            if busy then return end
            if cachedLink then
                local copied = copyToClipboard(cachedLink)
                ui:SetStatus(copied and "Link copied to clipboard again!"
                    or "Copy the link above, finish the checkpoint, then paste your key.", "ok")
                return
            end
            busy = true
            ui:SetBusy(true)
            ui:SetStatus("Generating your key link...", "info")
            task.spawn(function()
                local link, err = getKeyLink(Junkie)
                if link then
                    cachedLink = link
                    ui:ShowLink(link)
                    local copied = copyToClipboard(link)
                    if copied then
                        ui:SetStatus("Link copied to clipboard! Open it in your browser, finish the checkpoint, then paste the key here.", "ok")
                    else
                        ui:SetStatus("Copy the link above, open it in your browser, finish the checkpoint, then paste the key here.", "ok")
                    end
                else
                    ui:SetStatus(describe(err), err == "RATE_LIMITED" and "warn" or "err")
                end
                busy = false
                ui:SetBusy(false)
            end)
        end,

        onCheck = function(text)
            if busy then return end
            local key = trim(text)
            if #key == 0 then
                ui:SetStatus("Please paste your key first.", "err")
                return
            end
            busy = true
            ui:SetBusy(true)
            ui:SetStatus("Checking key...", "info")
            task.spawn(function()
                local valid, code = checkKey(Junkie, key)
                if valid then
                    ui:SetStatus("Key valid! Loading script...", "ok")
                    saveKey(key)
                    resultCode = code
                    result = key
                else
                    ui:SetStatus(describe(code), "err")
                    if code == "HWID_BANNED" then
                        result = false
                        kick(ERROR_TEXT.HWID_BANNED)
                    end
                end
                busy = false
                ui:SetBusy(false)
            end)
        end,

        onClose = function()
            result = false
        end,
    })

    repeat task.wait(0.1) until result ~= nil

    task.wait(0.4)
    ui:Destroy()

    if result == false then
        return nil
    end
    return result, resultCode
end

if JUNKIE.ENABLED then
    local key, code = runKeySystem()
    if not key then
        return
    end
    getgenv().SCRIPT_KEY = key
    notify(BRAND, code == "KEYLESS" and "Keyless mode active. Loading..." or "Key valid! Loading script...", 3)
end

-- =====================================================================
--  3) LOAD GAME SCRIPT  (Layer 2: ipasa ang ?key= para ma-verify ng _worker.js)
-- =====================================================================
local function urlEncode(str)
    return tostring(str):gsub("([^%w%-%_%.%~])", function(c)
        return string.format("%%%02X", string.byte(c))
    end)
end

local finalUrl = scriptUrl
do
    local k = getgenv().SCRIPT_KEY
    if type(k) == "string" and #trim(k) > 0 then
        local sep = finalUrl:find("?", 1, true) and "&" or "?"
        finalUrl = finalUrl .. sep .. "key=" .. urlEncode(k)
    end
end

local content, httpErr = httpGet(finalUrl)

if not content or #content == 0 then
    kick("Failed to load script (empty response). Please re-execute." .. (httpErr and ("\n" .. httpErr) or ""))
    return
end

-- Detect HTML error pages (Cloudflare 404/500/1020/WAF)
if content:sub(1, 1) == "<" then
    kick("Failed to load script (server returned HTML - baka 404 o na-block).\nURL: " .. tostring(finalUrl):gsub("key=[^&]+", "key=***") .. (httpErr and ("\n" .. httpErr) or ""))
    return
end

-- Detect Layer 2 gate error responses from _worker.js (nagsisimula sa "-- [BRAND]" at may error() sa dulo)
local gateReason = content:match("^%-%- %[" .. BRAND .. "%] Access Denied: ([^\n]+)")
    or content:match("^%-%- %[" .. BRAND .. "%] Key verification failed: ([^\n]+)")
if gateReason then
    -- Baka ang naka-save na key ay invalid/expired na -> burahin para bumalik sa key UI sa susunod na execute
    clearSavedKey()
    kick("Key verification failed: " .. gateReason .. "\nPlease re-execute and enter a new key.")
    return
end

local fn, err = loadstring(content)
if not fn then
    -- Ipakita ang unang linya para ma-debug agad (hal. "-- [efg2g] ..." error message)
    local firstLine = content:match("^([^\n]*)")
    kick("Compile error: " .. tostring(err) .. "\nFirst line: " .. tostring(firstLine))
    return
end

local okRun, runErr = pcall(fn)
if not okRun then
    -- Runtime error sa loob ng game script; huwag mag-kick, mag-warn lang
    -- (ang kick ay maka-kick sa player kahit successful naman ang load)
    warn("[" .. BRAND .. "] Script error: " .. tostring(runErr))
end
