local addonName, addonTable = ...
local MY_FONT = "Interface\\AddOns\\GuildCasino\\Roboto-Bold.ttf"
local MAX_OFFICER_RANK = 1
local ADDON_VERSION = "1.0"

local currentTab = 1
local listItems = {}
local classCache = {}
local playChips = 0
local isSyncing = false
local someoneElseIsSyncing = false
local hasWarnedUpdate = false

local GC_L = (addonTable and addonTable.GC_L) or _G.GC_L or function(key) return key end
local GC_GetLanguage = (addonTable and addonTable.GC_GetLanguage) or _G.GC_GetLanguage or function() return "enUS" end
local GC_GetLanguageButtonText = (addonTable and addonTable.GC_GetLanguageButtonText) or _G.GC_GetLanguageButtonText or function() return "Language: English" end
local GC_SetLanguage = (addonTable and addonTable.GC_SetLanguage) or _G.GC_SetLanguage or function(lang)
    GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
    GuildCasino_DB_V1["language"] = (lang == "huHU") and "huHU" or "enUS"
    return GuildCasino_DB_V1["language"]
end

local GC_LocalizedButtons = {}
local GC_LocalizedFontStrings = {}
local UpdateCasinoList
local playgroundPanel
local scrollFrame
local GC_RefreshGameLanguage
local StopDoubleSound = function() end

local function GC_RegisterLocalizedFontString(fontString, localeKey, prefix, suffix)
    if fontString and localeKey then
        fontString._gcLocaleKey = localeKey
        fontString._gcLocalePrefix = prefix or ""
        fontString._gcLocaleSuffix = suffix or ""
        table.insert(GC_LocalizedFontStrings, fontString)
        if fontString.SetText then
            fontString:SetText((prefix or "") .. GC_L(localeKey) .. (suffix or ""))
        end
    end
    return fontString
end

local function GC_RefreshLocalizedFontStrings()
    for _, fontString in ipairs(GC_LocalizedFontStrings) do
        if fontString and fontString._gcLocaleKey and fontString.SetText then
            fontString:SetText((fontString._gcLocalePrefix or "") .. GC_L(fontString._gcLocaleKey) .. (fontString._gcLocaleSuffix or ""))
        end
    end
end

local function GC_RegisterLocalizedButton(btn, localeKey)
    if btn and localeKey then
        btn._gcLocaleKey = localeKey
        table.insert(GC_LocalizedButtons, btn)
    end
    return btn
end

local function GC_RefreshLocalizedButtons()
    for _, btn in ipairs(GC_LocalizedButtons) do
        if btn and btn._gcLocaleKey and btn.SetText then
            btn:SetText(GC_L(btn._gcLocaleKey))
        end
    end
end

local function SetCustomFont(fontString, size, outline)
    if not fontString then return end
    fontString:SetFont(MY_FONT, size or 12, outline or "")
end

local msgQueue = {}
local isQueueRunning = false
local queueRetryCount = 0

local function ProcessMsgQueue()
    if #msgQueue == 0 then
        isQueueRunning = false
        queueRetryCount = 0
        return
    end

    local msgData = msgQueue[1]
    local sentSuccessfully = C_ChatInfo.SendAddonMessage(msgData.prefix, msgData.text, msgData.channel)

    if sentSuccessfully then
        table.remove(msgQueue, 1)
        queueRetryCount = 0
        C_Timer.After(0.3, ProcessMsgQueue)
    else
        queueRetryCount = queueRetryCount + 1
        local delay = 1.0
        if queueRetryCount > 5 then delay = 4.0 end
        C_Timer.After(delay, ProcessMsgQueue)
    end
end

local function QueueAddonMessage(prefix, text, channel)
    table.insert(msgQueue, {prefix = prefix, text = text, channel = channel})
    if not isQueueRunning then
        isQueueRunning = true
        ProcessMsgQueue()
    end
end

local function PlayCasinoSound(soundID)
    if GuildCasino_DB_V1 and GuildCasino_DB_V1["isMuted"] then return end
    PlaySound(soundID)
end

local function PlayCasinoFile(filePath)
    if GuildCasino_DB_V1 and GuildCasino_DB_V1["isMuted"] then return false, nil end
    return PlaySoundFile(filePath, "Master")
end

local function CreateModernButton(parent, text, width, height)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(width, height)

    local bg = btn:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.15, 0.15, 0.15, 0.9)
    btn.bg = bg

    local hl = btn:CreateTexture(nil, "HIGHLIGHT")
    hl:SetAllPoints()
    hl:SetColorTexture(0.3, 0.3, 0.3, 0.5)
    btn.hl = hl

    local fs = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    fs:SetPoint("CENTER", btn, "CENTER", 0, 0)
    SetCustomFont(fs, 12)
    fs:SetText(text)
    btn:SetFontString(fs)

    hooksecurefunc(btn, "Disable", function(self)
        if self.bg then self.bg:SetColorTexture(0.1, 0.1, 0.1, 0.5) end
        if self:GetFontString() then self:GetFontString():SetTextColor(0.5, 0.5, 0.5) end
    end)

    hooksecurefunc(btn, "Enable", function(self)
        if self.bg then self.bg:SetColorTexture(0.15, 0.15, 0.15, 0.9) end
        if self:GetFontString() then self:GetFontString():SetTextColor(1, 1, 1) end
    end)

    return btn
end

local function CreateLocalizedButton(parent, localeKey, width, height)
    return GC_RegisterLocalizedButton(CreateModernButton(parent, GC_L(localeKey), width, height), localeKey)
end

local function CleanName(name)
    if type(name) ~= "string" then return "" end
    local n = string.match(name, "([^-]+)") or name
    n = string.gsub(n, "%(%*%)", "")
    n = string.gsub(n, "%*", "")
    n = string.match(n, "^%s*(.-)%s*$")
    return n
end

local function UpdateClassCache()
    if IsInGuild() then
        for i = 1, GetNumGuildMembers() do
            local name, _, _, _, _, _, _, _, _, _, classFileName = GetGuildRosterInfo(i)
            if name and classFileName then
                classCache[CleanName(name)] = classFileName
            end
        end
    end

    local num = GetNumGroupMembers()
    if num > 0 then
        local prefix = IsInRaid() and "raid" or "party"
        for i = 1, num do
            local name = GetUnitName(prefix..i, false)
            local _, classFileName = UnitClass(prefix..i)
            if name and classFileName then
                classCache[CleanName(name)] = classFileName
            end
        end
    end

    local myName = UnitName("player")
    local _, myClassFile = UnitClass("player")
    if myName and myClassFile then
        classCache[CleanName(myName)] = myClassFile
    end
end

local function GetClassHexColor(name)
    local classFile = classCache[name]
    if classFile then
        local colorObj = C_ClassColor.GetClassColor(classFile)
        if colorObj then
            return string.format("FF%02x%02x%02x", colorObj.r * 255, colorObj.g * 255, colorObj.b * 255)
        end
    end
    return "FFFFCC00"
end

local function ColorName(name)
    return "|c" .. GetClassHexColor(name) .. name .. "|r"
end

local UIFrame

local function SetLastUpdate(timeStr)
    GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
    local t = timeStr or date("%Y.%m.%d %H:%M:%S")
    GuildCasino_DB_V1["lastUpdate"] = t
    if UIFrame and UIFrame.lastUpdateLabel then
        UIFrame.lastUpdateLabel:SetText(GC_L("LOC_0041") .. t)
    end
end

local function IsPlayerAdmin()
    if not IsInGuild() then return true end
    local _, _, rankIndex = GetGuildInfo("player")
    return rankIndex and rankIndex <= MAX_OFFICER_RANK
end

local function IsSenderAdmin(senderFullName)
    local shortSender = CleanName(senderFullName)
    if shortSender == CleanName(UnitName("player")) then return IsPlayerAdmin() end
    local numMembers = GetNumGuildMembers()
    if numMembers == 0 then C_GuildInfo.GuildRoster() end
    for i = 1, GetNumGuildMembers() do
        local name, _, rankIndex = GetGuildRosterInfo(i)
        if name and CleanName(name) == shortSender then
            return rankIndex and rankIndex <= MAX_OFFICER_RANK
        end
    end
    return false
end

local function AddChipTransaction(playerName, amount, gameName)
    if math.abs(amount) < 1000 then return end
    GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = GuildCasino_DB_V1["CHIP_TRANSACTIONS"] or {}

    local timeStr = date("%m.%d %H:%M")
    local actionText = amount > 0 and GC_L("LOC_0089") or GC_L("LOC_0090")
    local color = amount > 0 and "|cFF00FF00" or "|cFFFF0000"
    local logMsg = "["..timeStr.."] " .. playerName .. " " .. color .. actionText .. " " .. math.abs(amount) .. GC_L("LOC_0097") .. gameName .. ")"
    local id = date("%Y%m%d%H%M%S") .. "_" .. playerName .. "_" .. math.random(10000, 99999)

    GuildCasino_DB_V1["CHIP_TRANSACTIONS"][id] = {
        id = id,
        player = playerName,
        amount = amount,
        gameName = gameName,
        logMsg = logMsg,
    }

    SetLastUpdate()

    if IsInGuild() then
        QueueAddonMessage("GUILDCASINO", "CTX:" .. id .. "|" .. playerName .. "|" .. amount .. "|" .. gameName, "GUILD")
    end

    if currentTab == 3 and UpdateCasinoList then
        UpdateCasinoList()
    end
end

C_ChatInfo.RegisterAddonMessagePrefix("GUILDCASINO")

StaticPopupDialogs["GUILDCASINO_WIPECHIPS"] = {
    text = GC_L("LOC_0190"),
    button1 = GC_L("LOC_0191"),
    button2 = GC_L("LOC_0192"),
    OnAccept = function()
        GuildCasino_DB_V1["CHIPS"] = {}
        GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = {}
        GuildCasino_DB_V1["ChipSeason"] = (GuildCasino_DB_V1["ChipSeason"] or 1) + 1

        playChips = 1000
        GuildCasino_DB_V1["CHIPS"][CleanName(UnitName("player"))] = playChips

        if playgroundPanel and playgroundPanel.chipsDisplay then
            playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0199") .. playChips .. "|r")
        end

        SetLastUpdate()

        if IsInGuild() then
            QueueAddonMessage("GUILDCASINO", "WIPE_CHIPS:"..GuildCasino_DB_V1["ChipSeason"], "GUILD")
            SendChatMessage(GC_L("LOC_0208"), "GUILD")
        end

        if UpdateCasinoList then UpdateCasinoList() end
    end,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
}

local function GC_RefreshStaticPopups()
    local popup = StaticPopupDialogs["GUILDCASINO_WIPECHIPS"]
    if popup then
        popup.text = GC_L("LOC_0190")
        popup.button1 = GC_L("LOC_0191")
        popup.button2 = GC_L("LOC_0192")
    end
end

UIFrame = CreateFrame("Frame", "GuildCasino_GUI", UIParent, "BasicFrameTemplateWithInset")
UIFrame:SetSize(850, 800); UIFrame:SetPoint("CENTER", UIParent, "CENTER"); UIFrame:Hide()
UIFrame:SetFrameStrata("DIALOG")
UIFrame:SetFrameLevel(100)
UIFrame:SetScale(0.9)
UIFrame:SetMovable(true); UIFrame:EnableMouse(true); UIFrame:RegisterForDrag("LeftButton")
UIFrame:SetScript("OnDragStart", function(self) if self:IsMovable() then self:StartMoving() end end)
UIFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
UIFrame:SetResizable(true)
if UIFrame.SetResizeBounds then UIFrame:SetResizeBounds(850, 800, 1200, 900) else UIFrame:SetMinResize(850, 800); UIFrame:SetMaxResize(1200, 900) end

UIFrame.resizeBtn = CreateFrame("Button", nil, UIFrame)
UIFrame.resizeBtn:SetSize(16, 16); UIFrame.resizeBtn:SetPoint("BOTTOMRIGHT", UIFrame, "BOTTOMRIGHT", -4, 4)
UIFrame.resizeBtn:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
UIFrame.resizeBtn:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
UIFrame.resizeBtn:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
UIFrame.resizeBtn:SetScript("OnMouseDown", function(self, button) if button == "LeftButton" then UIFrame:StartSizing("BOTTOMRIGHT") end end)
UIFrame.resizeBtn:SetScript("OnMouseUp", function(self, button) UIFrame:StopMovingOrSizing() end)

UIFrame.title = UIFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
UIFrame.title:SetPoint("CENTER", UIFrame.TitleBg, "CENTER", 0, 0)
SetCustomFont(UIFrame.title, 14, "OUTLINE")
UIFrame.title:SetText(GC_L("LOC_0249") .. ADDON_VERSION)



UIFrame.sidebar = CreateFrame("Frame", nil, UIFrame)
UIFrame.sidebar:SetWidth(120)
UIFrame.sidebar:SetPoint("TOPLEFT", UIFrame, "TOPLEFT", 10, -40)
UIFrame.sidebar:SetPoint("BOTTOMLEFT", UIFrame, "BOTTOMLEFT", 10, 15)

UIFrame.uiTabs = {}
UIFrame.uiTabs[1] = CreateLocalizedButton(UIFrame.sidebar, "LOC_0263", 115, 30)
UIFrame.uiTabs[1]:SetPoint("TOP", UIFrame.sidebar, "TOP", 0, 0)
UIFrame.uiTabs[2] = CreateLocalizedButton(UIFrame.sidebar, "LOC_0266", 115, 30)
UIFrame.uiTabs[2]:SetPoint("TOP", UIFrame.uiTabs[1], "BOTTOM", 0, -5)
UIFrame.uiTabs[3] = CreateLocalizedButton(UIFrame.sidebar, "LOC_0269", 115, 30)
UIFrame.uiTabs[3]:SetPoint("TOP", UIFrame.uiTabs[2], "BOTTOM", 0, -5)

UIFrame.sidebar.divider = UIFrame:CreateTexture(nil, "ARTWORK")
UIFrame.sidebar.divider:SetColorTexture(1, 1, 1, 0.2)
UIFrame.sidebar.divider:SetWidth(1)
UIFrame.sidebar.divider:SetPoint("TOPLEFT", UIFrame.sidebar, "TOPRIGHT", 5, 0)
UIFrame.sidebar.divider:SetPoint("BOTTOMLEFT", UIFrame.sidebar, "BOTTOMRIGHT", 5, 0)

UIFrame.lastUpdateLabel = UIFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
UIFrame.lastUpdateLabel:SetPoint("BOTTOMRIGHT", UIFrame, "BOTTOMRIGHT", -15, 12)
SetCustomFont(UIFrame.lastUpdateLabel, 10)
UIFrame.lastUpdateLabel:SetText(GC_L("LOC_0041") .. (GuildCasino_DB_V1 and GuildCasino_DB_V1["lastUpdate"] or "-"))

UIFrame.resetChipsBtn = CreateLocalizedButton(UIFrame, "LOC_3724", 150, 28)
UIFrame.resetChipsBtn:SetPoint("BOTTOMLEFT", UIFrame, "BOTTOMLEFT", 150, 12)
UIFrame.resetChipsBtn.bg:SetColorTexture(0.6, 0.1, 0.1, 0.9)
UIFrame.resetChipsBtn:SetScript("OnClick", function()
    if not IsPlayerAdmin() then return end
    StaticPopup_Show("GUILDCASINO_WIPECHIPS")
end)

UIFrame.scaleSlider = CreateFrame("Slider", "GuildCasino_ScaleSlider", UIFrame.sidebar, "OptionsSliderTemplate")
UIFrame.scaleSlider:SetWidth(100)
UIFrame.scaleSlider:SetPoint("BOTTOM", UIFrame.sidebar, "BOTTOM", 0, 15)
UIFrame.scaleSlider:SetMinMaxValues(0.5, 1.5)
UIFrame.scaleSlider:SetValueStep(0.05)
UIFrame.scaleSlider:SetObeyStepOnDrag(true)

_G[UIFrame.scaleSlider:GetName() .. "Low"]:SetText("50%")
_G[UIFrame.scaleSlider:GetName() .. "High"]:SetText("150%")
_G[UIFrame.scaleSlider:GetName() .. "Text"]:SetText(GC_L("LOC_0302"))

UIFrame.scaleSlider.valText = UIFrame.scaleSlider:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
UIFrame.scaleSlider.valText:SetPoint("TOP", UIFrame.scaleSlider, "BOTTOM", 0, -2)

UIFrame.scaleSlider:SetValue(1.0)
UIFrame:SetScale(1.0)
UIFrame.scaleSlider.valText:SetText("100%")

UIFrame.scaleSlider:SetScript("OnValueChanged", function(self, value)
    local exactValue = math.floor(value * 100 + 0.5) / 100
    self.valText:SetText(math.floor(exactValue * 100) .. "%")
end)

UIFrame.scaleSlider:SetScript("OnMouseUp", function(self)
    local exactValue = math.floor(self:GetValue() * 100 + 0.5) / 100
    UIFrame:SetScale(exactValue)
end)

local function GC_RefreshLanguageDropdown()
    if UIFrame and UIFrame.langDropdown then
        UIFrame.langDropdown:SetText(GC_GetLanguageButtonText() .. "  v")
    end
    if UIFrame and UIFrame.langOptionEn then
        local lang = GC_GetLanguage()
        UIFrame.langOptionEn:SetText((lang == "enUS" and "> " or "  ") .. GC_L("LOC_LANGUAGE_EN_OPTION"))
        UIFrame.langOptionHu:SetText((lang == "huHU" and "> " or "  ") .. GC_L("LOC_LANGUAGE_HU_OPTION"))
    end
end

local function GC_RefreshLanguageTexts()
    GC_RefreshStaticPopups()
    GC_RefreshLocalizedButtons()
    GC_RefreshLocalizedFontStrings()
    GC_RefreshLanguageDropdown()

    if UIFrame and UIFrame.title then
        UIFrame.title:SetText(GC_L("LOC_0249") .. ADDON_VERSION)
    end

    if UIFrame and UIFrame.lastUpdateLabel then
        UIFrame.lastUpdateLabel:SetText(GC_L("LOC_0041") .. (GuildCasino_DB_V1["lastUpdate"] or "-"))
    end

    if playgroundPanel and playgroundPanel.chipsDisplay then
        playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0538") .. playChips .. "|r")
    end

    if GC_RefreshGameLanguage then
        GC_RefreshGameLanguage()
    end

    if UpdateCasinoList and UIFrame and UIFrame:IsShown() then
        UpdateCasinoList()
    end
end

UIFrame.langDropdown = CreateModernButton(UIFrame.sidebar, "", 115, 26)
UIFrame.langDropdown:SetPoint("BOTTOM", UIFrame.sidebar, "BOTTOM", 0, 65)

UIFrame.langMenu = CreateFrame("Frame", nil, UIFrame.sidebar)
UIFrame.langMenu:SetPoint("BOTTOM", UIFrame.langDropdown, "TOP", 0, 4)
UIFrame.langMenu:SetSize(115, 54)
UIFrame.langMenu:Hide()
UIFrame.langMenu.bg = UIFrame.langMenu:CreateTexture(nil, "BACKGROUND")
UIFrame.langMenu.bg:SetAllPoints()
UIFrame.langMenu.bg:SetColorTexture(0.05, 0.05, 0.05, 0.95)

UIFrame.langOptionEn = CreateModernButton(UIFrame.langMenu, "", 110, 24)
UIFrame.langOptionEn:SetPoint("TOP", UIFrame.langMenu, "TOP", 0, -3)
UIFrame.langOptionHu = CreateModernButton(UIFrame.langMenu, "", 110, 24)
UIFrame.langOptionHu:SetPoint("TOP", UIFrame.langOptionEn, "BOTTOM", 0, -2)

UIFrame.langOptionEn:SetScript("OnClick", function()
    GC_SetLanguage("enUS")
    UIFrame.langMenu:Hide()
    GC_RefreshLanguageTexts()
end)

UIFrame.langOptionHu:SetScript("OnClick", function()
    GC_SetLanguage("huHU")
    UIFrame.langMenu:Hide()
    GC_RefreshLanguageTexts()
end)

UIFrame.langDropdown:SetScript("OnClick", function()
    if UIFrame.langMenu:IsShown() then UIFrame.langMenu:Hide() else UIFrame.langMenu:Show() end
end)

GC_RefreshLanguageDropdown()

scrollFrame = CreateFrame("ScrollFrame", "GuildCasino_ScrollFrame", UIFrame, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", UIFrame, "TOPLEFT", 140, -40)
scrollFrame:SetPoint("BOTTOMRIGHT", UIFrame, "BOTTOMRIGHT", -25, 50)
scrollFrame:Hide()
scrollFrame.child = CreateFrame("Frame", nil, scrollFrame)
scrollFrame:SetScrollChild(scrollFrame.child)
scrollFrame:SetScript("OnSizeChanged", function(self, width)
    scrollFrame.child:SetWidth(width)
    for _, btn in pairs(listItems) do
        btn:SetWidth(width)
    end
end)


-- Casino games
playgroundPanel = CreateFrame("Frame", nil, UIFrame)
playgroundPanel:SetPoint("TOPLEFT", UIFrame, "TOPLEFT", 140, -40); playgroundPanel:SetPoint("BOTTOMRIGHT", UIFrame, "BOTTOMRIGHT", -25, 50); playgroundPanel:Hide()
playgroundPanel.title = playgroundPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
playgroundPanel.title:SetPoint("TOP", playgroundPanel, "TOP", 0, -10); SetCustomFont(playgroundPanel.title, 20, "OUTLINE"); GC_RegisterLocalizedFontString(playgroundPanel.title, "LOC_0518"); playgroundPanel.title:SetTextColor(1, 0.8, 0)
playgroundPanel.subtitle = playgroundPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
playgroundPanel.subtitle:SetPoint("TOP", playgroundPanel.title, "BOTTOM", 0, -5); SetCustomFont(playgroundPanel.subtitle, 12); GC_RegisterLocalizedFontString(playgroundPanel.subtitle, "LOC_0523")



local function GetMyChips()
    local name = CleanName(UnitName("player"))
    GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
    if not GuildCasino_DB_V1["CHIPS"][name] then GuildCasino_DB_V1["CHIPS"][name] = 1000 end
    return GuildCasino_DB_V1["CHIPS"][name]
end

playgroundPanel.chipsContainer = CreateFrame("Frame", nil, playgroundPanel)
playgroundPanel.chipsContainer:SetSize(220, 30); playgroundPanel.chipsContainer:SetPoint("TOPRIGHT", playgroundPanel, "TOPRIGHT", -5, -5)
playgroundPanel.chipsDisplay = playgroundPanel.chipsContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
playgroundPanel.chipsDisplay:SetPoint("LEFT", playgroundPanel.chipsContainer, "LEFT", 0, 0); SetCustomFont(playgroundPanel.chipsDisplay, 14, "OUTLINE"); playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0538") .. playChips .. "|r")

local function UpdatePlayChips(amount)
    local name = CleanName(UnitName("player")); GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
    playChips = playChips + amount; GuildCasino_DB_V1["CHIPS"][name] = playChips
    playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0544") .. playChips .. "|r")
    if IsInGuild() then C_ChatInfo.SendAddonMessage("GUILDCASINO", "SET_CHIP:"..name..":"..playChips, "GUILD") end
end

playgroundPanel.btnRefillChips = CreateLocalizedButton(playgroundPanel.chipsContainer, "LOC_0550", 65, 25)
playgroundPanel.btnRefillChips:SetPoint("RIGHT", playgroundPanel.chipsContainer, "RIGHT", 0, 0)
playgroundPanel.btnRefillChips:SetScript("OnClick", function()
    if playChips < 10 then UpdatePlayChips(1000); print(GC_L("LOC_0554"))
    else print(GC_L("LOC_0555")) end
end)


playgroundPanel.announceCheck = CreateFrame("CheckButton", nil, playgroundPanel, "UICheckButtonTemplate")
playgroundPanel.announceCheck:SetSize(24, 24); playgroundPanel.announceCheck:SetPoint("TOPRIGHT", playgroundPanel.chipsContainer, "BOTTOMRIGHT", 0, 0)
playgroundPanel.announceLabel = playgroundPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
playgroundPanel.announceLabel:SetPoint("RIGHT", playgroundPanel.announceCheck, "LEFT", -5, 0); SetCustomFont(playgroundPanel.announceLabel, 10); GC_RegisterLocalizedFontString(playgroundPanel.announceLabel, "LOC_0575")
playgroundPanel.muteCheck = CreateFrame("CheckButton", nil, playgroundPanel, "UICheckButtonTemplate")
playgroundPanel.muteCheck:SetSize(24, 24); playgroundPanel.muteCheck:SetPoint("TOPLEFT", playgroundPanel, "TOPLEFT", 10, -5)
playgroundPanel.muteLabel = playgroundPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
playgroundPanel.muteLabel:SetPoint("LEFT", playgroundPanel.muteCheck, "RIGHT", -5, 0); SetCustomFont(playgroundPanel.muteLabel, 10); GC_RegisterLocalizedFontString(playgroundPanel.muteLabel, "LOC_0584")
playgroundPanel.muteCheck:SetScript("OnClick", function(self)
    local isMuted = self:GetChecked(); GuildCasino_DB_V1["isMuted"] = isMuted; if isMuted then StopDoubleSound() end
end)

local function AnnounceGameWin(gameName, amount)
    if playgroundPanel.announceCheck:GetChecked() and IsInGroup() then
        local channel = IsInRaid() and "RAID" or "PARTY"
        SendChatMessage("GuildCasino: " .. UnitName("player") .. " " .. gameName .. GC_L("LOC_0592") .. amount .. GC_L("LOC_0593"), channel)
    end
end

playgroundPanel.iconsFrame = CreateFrame("Frame", nil, playgroundPanel); playgroundPanel.iconsFrame:SetAllPoints()
playgroundPanel.gameOverlay = CreateFrame("Frame", nil, playgroundPanel); playgroundPanel.gameOverlay:SetAllPoints(); playgroundPanel.gameOverlay:Hide()
playgroundPanel.closeGameBtn = CreateLocalizedButton(playgroundPanel.gameOverlay, "LOC_0596", 150, 25)
playgroundPanel.closeGameBtn:SetPoint("BOTTOM", playgroundPanel.gameOverlay, "BOTTOM", 0, 10)
playgroundPanel.closeGameBtn:SetScript("OnClick", function()
    playgroundPanel.gameOverlay:Hide()
    for _, child in ipairs({playgroundPanel.gameOverlay:GetChildren()}) do
        if child ~= playgroundPanel.closeGameBtn and child ~= playgroundPanel.chipsContainer then child:Hide() end
    end
    playgroundPanel.chipsContainer:SetParent(playgroundPanel); playgroundPanel.iconsFrame:Show() 
end)

local function CreateGameIcon(parent, title, iconTexture, xOffset, yOffset, onClick)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(60, 60)
    btn:SetPoint("TOP", playgroundPanel.title, "BOTTOM", xOffset, yOffset)
    local tex = btn:CreateTexture(nil, "BACKGROUND"); tex:SetAllPoints(); tex:SetTexture(iconTexture)
    local hl = btn:CreateTexture(nil, "HIGHLIGHT"); hl:SetAllPoints(); hl:SetColorTexture(1, 1, 1, 0.2)
    local fs = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    fs:SetPoint("TOP", btn, "BOTTOM", 0, -8)
    SetCustomFont(fs, 12, "OUTLINE")
    if type(title) == "string" and string.match(title, "^LOC_") then
        GC_RegisterLocalizedFontString(fs, title)
    else
        fs:SetText(title)
    end
    btn:SetScript("OnClick", function() playgroundPanel.chipsContainer:SetParent(playgroundPanel.gameOverlay); onClick() end)
    return btn
end

local slotFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); slotFrame:SetAllPoints(); slotFrame:Hide()
do
    slotFrame.bg = slotFrame:CreateTexture(nil, "BACKGROUND"); slotFrame.bg:SetSize(572, 594); slotFrame.bg:SetPoint("CENTER", slotFrame, "CENTER", 0, 10); slotFrame.bg:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\slot_bg.tga")
    slotFrame.iconsList = { "Interface\\AddOns\\GuildCasino\\Images\\sm1", "Interface\\AddOns\\GuildCasino\\Images\\sm2", "Interface\\AddOns\\GuildCasino\\Images\\sm3", "Interface\\AddOns\\GuildCasino\\Images\\sm4" }
    slotFrame.boxes = {}; local iconSize, startX, startY, spacingX, spacingY = 60, -120, -45, 120, 60
    
    for row = 1, 3 do
        slotFrame.boxes[row] = {}
        for col = 1, 3 do
            local f = slotFrame:CreateTexture(nil, "OVERLAY"); f:SetSize(iconSize, iconSize); f:SetPoint("CENTER", slotFrame, "CENTER", startX + ((col - 1) * spacingX), startY - ((row - 1) * spacingY)); f:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            slotFrame.boxes[row][col] = f
        end
    end
    
    slotFrame.winLines = {}
    for i = 1, 5 do
        local line = slotFrame:CreateLine(nil, "OVERLAY")
        line:SetColorTexture(1, 0, 0, 0.9)
        line:SetThickness(6)
        line:Hide()
        slotFrame.winLines[i] = line
    end

    slotFrame.result = slotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); slotFrame.result:SetPoint("CENTER", slotFrame, "CENTER", 185, -90); SetCustomFont(slotFrame.result, 16, "OUTLINE"); slotFrame.result:SetTextColor(1, 0.2, 0.2); slotFrame.result:SetText(GC_L("LOC_MANUAL_IDLE"))
    slotFrame.spinBtn = CreateLocalizedButton(slotFrame, "LOC_0631", 140, 40); slotFrame.spinBtn:SetPoint("BOTTOM", slotFrame, "BOTTOM", 0, 60)
    slotFrame.doubleBtn = CreateLocalizedButton(slotFrame, "LOC_0634", 140, 40); slotFrame.doubleBtn:SetPoint("RIGHT", slotFrame.spinBtn, "LEFT", -10, 0); slotFrame.doubleBtn:Hide()
    slotFrame.collectBtn = CreateLocalizedButton(slotFrame, "LOC_0637", 140, 40); slotFrame.collectBtn:SetPoint("LEFT", slotFrame.spinBtn, "RIGHT", 10, 0); slotFrame.collectBtn:Hide()
    slotFrame.isSpinning = false; slotFrame.currentWin = 0
    local currentDoubleSoundHandle = nil; local doubleLoopTicker = nil; local LOOP_TIME = 2.9 
    
    StopDoubleSound = function()
        if currentDoubleSoundHandle then StopSound(currentDoubleSoundHandle); currentDoubleSoundHandle = nil end
        if doubleLoopTicker then doubleLoopTicker:Cancel(); doubleLoopTicker = nil end
    end
    
    local function StartDoubleSound()
        StopDoubleSound() 
        local _, handle = PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\double_loop.mp3"); currentDoubleSoundHandle = handle
        doubleLoopTicker = C_Timer.NewTicker(LOOP_TIME, function() local _, nextHandle = PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\double_loop.mp3"); currentDoubleSoundHandle = nextHandle end)
    end
    
    slotFrame.doubleBtn:SetScript("OnClick", function()
        if slotFrame.currentWin <= 0 or playChips < slotFrame.currentWin then slotFrame.doubleBtn:Hide(); slotFrame.collectBtn:Hide(); return end
        UpdatePlayChips(-slotFrame.currentWin); StopDoubleSound() 
        if math.random(1, 100) <= 50 then
            slotFrame.currentWin = slotFrame.currentWin * 2; UpdatePlayChips(slotFrame.currentWin)
            slotFrame.result:SetText(GC_L("LOC_0643") .. slotFrame.currentWin); slotFrame.doubleBtn:SetText(GC_L("LOC_0644") .. slotFrame.currentWin .. ")"); slotFrame.collectBtn:SetText(GC_L("LOC_0646") .. slotFrame.currentWin .. ")")
            PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\double_win.mp3"); C_Timer.After(1.5, function() if slotFrame.doubleBtn:IsShown() then StartDoubleSound() end end); AnnounceGameWin(GC_L("LOC_0649"), slotFrame.currentWin)
        else
            slotFrame.result:SetText(GC_L("LOC_0650")); slotFrame.currentWin = 0; slotFrame.doubleBtn:Hide(); slotFrame.collectBtn:Hide(); PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\double_lose.mp3")
        end
    end)
    
    slotFrame.collectBtn:SetScript("OnClick", function()
        slotFrame.doubleBtn:Hide(); slotFrame.collectBtn:Hide(); slotFrame.result:SetText(GC_L("LOC_0653") .. slotFrame.currentWin); slotFrame.currentWin = 0; StopDoubleSound(); PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\collect.mp3")
    end)
    
    slotFrame.spinBtn:SetScript("OnClick", function()
        if slotFrame.isSpinning then return end
        if playChips < 20 then slotFrame.result:SetText(GC_L("LOC_0656")); return end
        
        for _, line in ipairs(slotFrame.winLines) do line:Hide() end
        
        slotFrame.doubleBtn:Hide(); slotFrame.collectBtn:Hide(); slotFrame.currentWin = 0; StopDoubleSound(); slotFrame.isSpinning = true; slotFrame.spinBtn:Disable(); UpdatePlayChips(-20); slotFrame.result:SetText(GC_L("LOC_0657")); PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        local results = {}; for r = 1, 3 do results[r] = { math.random(1, #slotFrame.iconsList), math.random(1, #slotFrame.iconsList), math.random(1, #slotFrame.iconsList) } end
        local tick = 0
        
        local function SpinReels()
            tick = tick + 1
            for col = 1, 3 do
                local stopTick = col * 10 
                if tick < stopTick then 
                    for row = 1, 3 do 
                        slotFrame.boxes[row][col]:SetTexture(slotFrame.iconsList[math.random(1, #slotFrame.iconsList)])
                        slotFrame.boxes[row][col]:SetVertexColor(1, 1, 1, 1) 
                    end
                elseif tick == stopTick then 
                    for row = 1, 3 do 
                        slotFrame.boxes[row][col]:SetTexture(slotFrame.iconsList[results[row][col]]) 
                    end
                    if tick == 10 or tick == 20 or tick == 30 then PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\stop.mp3") end 
                end
            end
            if tick < 30 then 
                C_Timer.After(0.08, SpinReels) 
            else
                slotFrame.isSpinning = false; slotFrame.spinBtn:Enable()
                local totalWin, lines = 0, { { {1,1}, {1,2}, {1,3} }, { {2,1}, {2,2}, {2,3} }, { {3,1}, {3,2}, {3,3} }, { {1,1}, {2,2}, {3,3} }, { {3,1}, {2,2}, {1,3} } }
                local lineIdx = 1
                
                for _, line in ipairs(lines) do
                    local r1, c1, r2, c2, r3, c3 = line[1][1], line[1][2], line[2][1], line[2][2], line[3][1], line[3][2]
                    if results[r1][c1] == results[r2][c2] and results[r2][c2] == results[r3][c3] then
                        totalWin = totalWin + 60
                        slotFrame.boxes[r1][c1]:SetVertexColor(0, 1, 0); slotFrame.boxes[r2][c2]:SetVertexColor(0, 1, 0); slotFrame.boxes[r3][c3]:SetVertexColor(0, 1, 0)

                        if slotFrame.winLines[lineIdx] then
                            slotFrame.winLines[lineIdx]:SetStartPoint("CENTER", slotFrame.boxes[r1][c1])
                            slotFrame.winLines[lineIdx]:SetEndPoint("CENTER", slotFrame.boxes[r3][c3])
                            slotFrame.winLines[lineIdx]:Show()
                            lineIdx = lineIdx + 1
                        end
                    end
                end
                
                if totalWin > 0 then
                    slotFrame.result:SetText(GC_L("LOC_0662") .. totalWin); UpdatePlayChips(totalWin); AnnounceGameWin("Super Dice Slot Machine", totalWin)
                    AddChipTransaction(CleanName(UnitName("player")), totalWin, GC_L("LOC_0665"))
                    
                    slotFrame.currentWin = totalWin; slotFrame.doubleBtn:SetText(GC_L("LOC_0666") .. slotFrame.currentWin .. ")"); slotFrame.collectBtn:SetText(GC_L("LOC_0668") .. slotFrame.currentWin .. ")"); slotFrame.doubleBtn:Show(); slotFrame.collectBtn:Show()
                    PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\slot_win.mp3"); C_Timer.After(0.7, function() if slotFrame.doubleBtn:IsShown() then StartDoubleSound() end end)
                else 
                    slotFrame.result:SetText(GC_L("LOC_0671")) 
                end
            end
        end
        SpinReels()
    end)
end

local rouletteFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); rouletteFrame:SetAllPoints(); rouletteFrame:Hide()
do
    rouletteFrame.isRed = {[1]=true,[3]=true,[5]=true,[7]=true,[9]=true,[12]=true,[14]=true,[16]=true,[18]=true,[19]=true,[21]=true,[23]=true,[25]=true,[27]=true,[30]=true,[32]=true,[34]=true,[36]=true}
    rouletteFrame.btns = {}
    rouletteFrame.placedBets = {} 
    rouletteFrame.totalBetAmount = 0    
    rouletteFrame.currentBetText = rouletteFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    rouletteFrame.currentBetText:SetPoint("TOP", rouletteFrame, "TOP", 0, -55)
    SetCustomFont(rouletteFrame.currentBetText, 14, "OUTLINE")
    rouletteFrame.currentBetText:SetText(GC_L("LOC_0678"))
    rouletteFrame.resultNum = rouletteFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    rouletteFrame.resultNum:SetPoint("CENTER", rouletteFrame, "CENTER", 0, 140)
    SetCustomFont(rouletteFrame.resultNum, 40, "OUTLINE")
    rouletteFrame.resultNum:SetText("")   
    rouletteFrame.resultText = rouletteFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    rouletteFrame.resultText:SetPoint("TOP", rouletteFrame.resultNum, "BOTTOM", 0, -5)
    SetCustomFont(rouletteFrame.resultText, 16, "OUTLINE")
    rouletteFrame.resultText:SetText(GC_L("LOC_0690"))
    
    local function UpdateBetText()
        rouletteFrame.currentBetText:SetText(GC_L("LOC_0691") .. rouletteFrame.totalBetAmount .. GC_L("LOC_0692"))
    end

    local function PlaceRouletteBet(bType, bTarget, bName, btn)
        if rouletteFrame.isSpinning then return end
        
        local amt = tonumber(rouletteFrame.betInput:GetText()) or 10
        if amt <= 0 then rouletteFrame.resultText:SetText(GC_L("LOC_0693")); return end
        
        if playChips < (rouletteFrame.totalBetAmount + amt) then
            rouletteFrame.resultText:SetText(GC_L("LOC_0694"))
            return
        end
        
        if not rouletteFrame.placedBets[btn] then
            rouletteFrame.placedBets[btn] = { bType = bType, bTarget = bTarget, bName = bName, amount = 0 }
        end
        
        rouletteFrame.placedBets[btn].amount = rouletteFrame.placedBets[btn].amount + amt
        rouletteFrame.totalBetAmount = rouletteFrame.totalBetAmount + amt
        
        btn.coinGroup:Show()
        btn.coinText:SetText(rouletteFrame.placedBets[btn].amount)
        
        UpdateBetText()
        PlaySound(856)
        rouletteFrame.resultText:SetText("|cFF00FF00" .. amt .. GC_L("LOC_0696") .. bName .. "|r")
    end

    local function ClearAllBets()
        rouletteFrame.placedBets = {}
        rouletteFrame.totalBetAmount = 0
        for _, b in ipairs(rouletteFrame.btns) do
            b.coinGroup:Hide()
            b.coinText:SetText("0")
        end
        UpdateBetText()
    end

    local function MakeRBtn(w, h, x, y, text, color, bType, bTarget, bName)
        local btn = CreateFrame("Button", nil, rouletteFrame); btn:SetSize(w, h); btn:SetPoint("CENTER", rouletteFrame, "CENTER", x, y)
        local border = btn:CreateTexture(nil, "BACKGROUND"); border:SetAllPoints(); border:SetColorTexture(1, 1, 1, 0.4) 
        local bg = btn:CreateTexture(nil, "ARTWORK"); bg:SetPoint("TOPLEFT", 1, -1); bg:SetPoint("BOTTOMRIGHT", -1, 1); bg:SetColorTexture(unpack(color))
        btn.hl = btn:CreateTexture(nil, "HIGHLIGHT"); btn.hl:SetAllPoints(); btn.hl:SetColorTexture(1, 1, 1, 0.1)
        local fs = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); fs:SetPoint("CENTER", 0, 0); SetCustomFont(fs, 12, "OUTLINE"); fs:SetText(text)
        
        btn.coinGroup = CreateFrame("Frame", nil, btn)
        btn.coinGroup:SetSize(20, 20)
        btn.coinGroup:SetPoint("TOPRIGHT", btn, "TOPRIGHT", 5, 5)
        btn.coinGroup:SetFrameLevel(btn:GetFrameLevel() + 2)
        
        btn.coinTex = btn.coinGroup:CreateTexture(nil, "BACKGROUND")
        btn.coinTex:SetAllPoints()
        btn.coinTex:SetTexture("Interface\\Icons\\INV_Misc_Coin_02")
        
        btn.coinBg = btn.coinGroup:CreateTexture(nil, "BORDER")
        btn.coinBg:SetPoint("CENTER", 0, 0)
        btn.coinBg:SetSize(24, 14)
        btn.coinBg:SetColorTexture(0, 0, 0, 0.7)

        btn.coinText = btn.coinGroup:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        btn.coinText:SetPoint("CENTER", 0, 0)
        SetCustomFont(btn.coinText, 10, "OUTLINE")
        btn.coinText:SetTextColor(1, 1, 0)
        
        btn.coinGroup:Hide()

        btn:SetScript("OnClick", function() PlaceRouletteBet(bType, bTarget, bName, btn) end)
        table.insert(rouletteFrame.btns, btn)
        return btn
    end
    
    MakeRBtn(30, 90, -165, 40, "0", {0, 0.6, 0}, "number", 0, GC_L("LOC_0725"))
    for col = 1, 12 do for row = 1, 3 do local num = (col - 1) * 3 + row; MakeRBtn(30, 30, -135 + (col - 1) * 30, 10 + (row - 1) * 30, tostring(num), rouletteFrame.isRed[num] and {0.7, 0, 0} or {0.1, 0.1, 0.1}, "number", num, GC_L("LOC_0727") .. num) end end
    MakeRBtn(120, 25, -90, -20, "1st 12", {0.2, 0.2, 0.2}, "dozen", 1, "1. Tucat (1-12)"); MakeRBtn(120, 25, 30, -20, "2nd 12", {0.2, 0.2, 0.2}, "dozen", 2, "2. Tucat (13-24)"); MakeRBtn(120, 25, 150, -20, "3rd 12", {0.2, 0.2, 0.2}, "dozen", 3, "3. Tucat (25-36)")
    MakeRBtn(60, 25, -120, -45, "1-18", {0.2, 0.2, 0.2}, "half", 1, "Kicsi (1-18)"); MakeRBtn(60, 25, -60, -45, GC_L("LOC_0740"), {0.2, 0.2, 0.2}, "evenodd", "even", GC_L("LOC_0743")); MakeRBtn(60, 25, 0, -45, GC_L("LOC_0744"), {0.7, 0, 0}, "color", "red", GC_L("LOC_0747"))
    MakeRBtn(60, 25, 60, -45, "Fekete", {0.1, 0.1, 0.1}, "color", "black", "Fekete"); MakeRBtn(60, 25, 120, -45, GC_L("LOC_0752"), {0.2, 0.2, 0.2}, "evenodd", "odd", GC_L("LOC_0755")); MakeRBtn(60, 25, 180, -45, "19-36", {0.2, 0.2, 0.2}, "half", 2, "Nagy (19-36)")
    
    rouletteFrame.spinBtn = CreateLocalizedButton(rouletteFrame, "LOC_0759", 150, 40)
    rouletteFrame.spinBtn:SetPoint("CENTER", rouletteFrame, "CENTER", 0, -100)
    rouletteFrame.isSpinning = false
    
    rouletteFrame.betInput = CreateFrame("EditBox", nil, rouletteFrame, "InputBoxTemplate")
    rouletteFrame.betInput:SetSize(60, 30)
    rouletteFrame.betInput:SetPoint("RIGHT", rouletteFrame.spinBtn, "LEFT", -30, 0)
    rouletteFrame.betInput:SetNumeric(true)
    rouletteFrame.betInput:SetAutoFocus(false)
    rouletteFrame.betInput:SetText("10")
    SetCustomFont(rouletteFrame.betInput, 14)
    local betLbl = rouletteFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    betLbl:SetPoint("BOTTOMLEFT", rouletteFrame.betInput, "TOPLEFT", 0, 2)
    SetCustomFont(betLbl, 10)
    GC_RegisterLocalizedFontString(betLbl, "LOC_0771")
    
    rouletteFrame.clearBtn = CreateLocalizedButton(rouletteFrame, "LOC_0772", 120, 30)
    rouletteFrame.clearBtn:SetPoint("LEFT", rouletteFrame.spinBtn, "RIGHT", 30, 0)
    rouletteFrame.clearBtn:SetScript("OnClick", function()
        if not rouletteFrame.isSpinning then 
            ClearAllBets() 
            rouletteFrame.resultText:SetText(GC_L("LOC_0776"))
        end
    end)

    rouletteFrame.spinBtn:SetScript("OnClick", function()
        if rouletteFrame.isSpinning then return end
        if rouletteFrame.totalBetAmount <= 0 then rouletteFrame.resultText:SetText(GC_L("LOC_0778")); return end
        if playChips < rouletteFrame.totalBetAmount then rouletteFrame.resultText:SetText(GC_L("LOC_0779")); return end
        
        rouletteFrame.isSpinning = true
        rouletteFrame.spinBtn:Disable()
        rouletteFrame.clearBtn:Disable()
        UpdatePlayChips(-rouletteFrame.totalBetAmount)
        
        local spinCount = 0
        C_Timer.NewTicker(0.1, function()
            spinCount = spinCount + 1
            local tempNum = math.random(0, 36)
            rouletteFrame.resultNum:SetText(tempNum)
            rouletteFrame.resultNum:SetTextColor(tempNum == 0 and 0 or (rouletteFrame.isRed[tempNum] and 1 or 0.5), tempNum == 0 and 1 or 0.5, tempNum == 0 and 0 or 0.5)
            rouletteFrame.resultText:SetText(GC_L("LOC_0780"))
            
            if spinCount >= 20 then
                rouletteFrame.isSpinning = false
                rouletteFrame.spinBtn:Enable()
                rouletteFrame.clearBtn:Enable()
                
                local num = math.random(0, 36)
                rouletteFrame.resultNum:SetText(num)
                rouletteFrame.resultNum:SetTextColor(num == 0 and 0 or (rouletteFrame.isRed[num] and 1 or 0.5), num == 0 and 1 or 0.5, num == 0 and 0 or 0.5)
                
                local totalWinAmount = 0
                
                for btn, bet in pairs(rouletteFrame.placedBets) do
                    local winAmount = 0
                    if bet.bType == "number" and num == bet.bTarget then winAmount = bet.amount * 36
                    elseif bet.bType == "color" and ((bet.bTarget == "red" and rouletteFrame.isRed[num]) or (bet.bTarget == "black" and num > 0 and not rouletteFrame.isRed[num])) then winAmount = bet.amount * 2
                    elseif bet.bType == "evenodd" and num > 0 and ((bet.bTarget == "even" and num % 2 == 0) or (bet.bTarget == "odd" and num % 2 == 1)) then winAmount = bet.amount * 2
                    elseif bet.bType == "half" and ((bet.bTarget == 1 and num >= 1 and num <= 18) or (bet.bTarget == 2 and num >= 19 and num <= 36)) then winAmount = bet.amount * 2
                    elseif bet.bType == "dozen" and ((bet.bTarget == 1 and num >= 1 and num <= 12) or (bet.bTarget == 2 and num >= 13 and num <= 24) or (bet.bTarget == 3 and num >= 25 and num <= 36)) then winAmount = bet.amount * 3 end
                    
                    if winAmount > 0 then
                        totalWinAmount = totalWinAmount + winAmount
                    end
                end
                
                if totalWinAmount > 0 then 
                    UpdatePlayChips(totalWinAmount)
                    rouletteFrame.resultText:SetText(GC_L("LOC_0790") .. totalWinAmount .. GC_L("LOC_0791"))
                    PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                    AnnounceGameWin(GC_L("LOC_0792") .. rouletteFrame.totalBetAmount .. ")", totalWinAmount)
                    AddChipTransaction(CleanName(UnitName("player")), totalWinAmount, "Rulett")
                else 
                    rouletteFrame.resultText:SetText(GC_L("LOC_0796")) 
                    AddChipTransaction(CleanName(UnitName("player")), -rouletteFrame.totalBetAmount, "Rulett")
                end
                
                ClearAllBets() 
            end
        end, 20)
    end)
end

local bjFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); bjFrame:SetAllPoints(); bjFrame:Hide()
do
    bjFrame.deck, bjFrame.playerHand, bjFrame.dealerHand, bjFrame.currentBet = {}, {}, {}, 0
    bjFrame.dealerText = bjFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); bjFrame.dealerText:SetPoint("CENTER", bjFrame, "CENTER", 0, 180); SetCustomFont(bjFrame.dealerText, 18, "OUTLINE"); bjFrame.dealerText:SetText(GC_L("LOC_0805"))
    bjFrame.resultText = bjFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); bjFrame.resultText:SetPoint("CENTER", bjFrame, "CENTER", 0, 10); SetCustomFont(bjFrame.resultText, 24, "OUTLINE"); bjFrame.resultText:SetText("BLACKJACK")
    bjFrame.playerText = bjFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); bjFrame.playerText:SetPoint("CENTER", bjFrame, "CENTER", 0, -160); SetCustomFont(bjFrame.playerText, 18, "OUTLINE"); bjFrame.playerText:SetText(GC_L("LOC_0817"))
    bjFrame.hitBtn = CreateLocalizedButton(bjFrame, "LOC_0818", 100, 30); bjFrame.hitBtn:SetPoint("CENTER", bjFrame, "CENTER", -55, -200)
    bjFrame.standBtn = CreateLocalizedButton(bjFrame, "LOC_0821", 100, 30); bjFrame.standBtn:SetPoint("CENTER", bjFrame, "CENTER", 55, -200)
    bjFrame.betInput = CreateFrame("EditBox", nil, bjFrame, "InputBoxTemplate"); bjFrame.betInput:SetSize(80, 30); bjFrame.betInput:SetPoint("CENTER", bjFrame, "CENTER", -50, -250); bjFrame.betInput:SetAutoFocus(false); bjFrame.betInput:SetNumeric(true); bjFrame.betInput:SetText("10"); SetCustomFont(bjFrame.betInput, 14)
    local lbl = bjFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); lbl:SetPoint("BOTTOMLEFT", bjFrame.betInput, "TOPLEFT", 0, 2); SetCustomFont(lbl, 10); GC_RegisterLocalizedFontString(lbl, "LOC_0833")
    bjFrame.startBtn = CreateLocalizedButton(bjFrame, "LOC_0834", 130, 30); bjFrame.startBtn:SetPoint("LEFT", bjFrame.betInput, "RIGHT", 15, 0)
    bjFrame.pFrames, bjFrame.dFrames = {}, {}
    
    local function CreateDeck() local newDeck = {}; for _, suit in ipairs({"C", "D", "H", "S"}) do for _, rankData in ipairs({{"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7}, {"8", 8}, {"9", 9}, {"10", 10}, {"J", 10}, {"Q", 10}, {"K", 10}, {"A", 11}}) do table.insert(newDeck, {rank = rankData[1], value = rankData[2], tex = rankData[1]..suit..".tga"}) end end; for i = #newDeck, 2, -1 do local j = math.random(i); newDeck[i], newDeck[j] = newDeck[j], newDeck[i] end; return newDeck end
    local function GetHandValue(hand) local total, aces = 0, 0; for _, card in ipairs(hand) do total = total + card.value; if card.rank == "A" then aces = aces + 1 end end; while total > 21 and aces > 0 do total = total - 10; aces = aces - 1 end; return total end
    function bjFrame.UpdateCardVisuals()
        for _, v in ipairs(bjFrame.pFrames) do v:Hide() end; for _, v in ipairs(bjFrame.dFrames) do v:Hide() end
        local pOffset = -((#bjFrame.playerHand - 1) * 75) / 2
        for i, card in ipairs(bjFrame.playerHand) do if not bjFrame.pFrames[i] then bjFrame.pFrames[i] = bjFrame:CreateTexture(nil, "ARTWORK"); bjFrame.pFrames[i]:SetSize(70, 140) end; bjFrame.pFrames[i]:SetPoint("CENTER", bjFrame, "CENTER", pOffset + ((i-1)*75), -70); bjFrame.pFrames[i]:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. card.tex); bjFrame.pFrames[i]:Show() end
        local dOffset = -((#bjFrame.dealerHand - 1) * 75) / 2
        for i, card in ipairs(bjFrame.dealerHand) do if not bjFrame.dFrames[i] then bjFrame.dFrames[i] = bjFrame:CreateTexture(nil, "ARTWORK"); bjFrame.dFrames[i]:SetSize(70, 140) end; bjFrame.dFrames[i]:SetPoint("CENTER", bjFrame, "CENTER", dOffset + ((i-1)*75), 90); bjFrame.dFrames[i]:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. card.tex); bjFrame.dFrames[i]:Show() end
    end
    local function EndBlackjack()
        bjFrame.hitBtn:Disable(); bjFrame.standBtn:Disable(); bjFrame.startBtn:Enable(); bjFrame.betInput:Enable()
        while GetHandValue(bjFrame.dealerHand) < 17 do table.insert(bjFrame.dealerHand, table.remove(bjFrame.deck)) end; bjFrame.UpdateCardVisuals() 
        local pTotal, dTotal = GetHandValue(bjFrame.playerHand), GetHandValue(bjFrame.dealerHand); bjFrame.dealerText:SetText(GC_L("LOC_0864") .. dTotal)
        local pName = CleanName(UnitName("player"))
        
        if pTotal > 21 then 
            bjFrame.resultText:SetText(GC_L("LOC_0866") .. bjFrame.currentBet .. ")|r")
            AddChipTransaction(pName, -bjFrame.currentBet, "Blackjack")
        elseif dTotal > 21 then 
            bjFrame.resultText:SetText(GC_L("LOC_0869") .. (bjFrame.currentBet * 2) .. GC_L("LOC_0870"))
            UpdatePlayChips(bjFrame.currentBet * 2)
            AddChipTransaction(pName, bjFrame.currentBet * 2, "Blackjack")
            AnnounceGameWin("Blackjack", bjFrame.currentBet * 2)
        elseif pTotal > dTotal then 
            local w = (pTotal == 21 and #bjFrame.playerHand == 2) and math.floor(bjFrame.currentBet * 2.5) or (bjFrame.currentBet * 2)
            bjFrame.resultText:SetText((w > bjFrame.currentBet * 2 and "|cFF00FFFFBLACKJACK! (+" or GC_L("LOC_0874")) .. w .. GC_L("LOC_0875"))
            UpdatePlayChips(w)
            AddChipTransaction(pName, w, "Blackjack")
            if w > bjFrame.currentBet * 2 then PlayCasinoSound(SOUNDKIT.RAID_WARNING) end; AnnounceGameWin("Blackjack", w)
        elseif dTotal > pTotal then 
            bjFrame.resultText:SetText(GC_L("LOC_0878") .. bjFrame.currentBet .. ")|r")
            AddChipTransaction(pName, -bjFrame.currentBet, "Blackjack")
        else 
            bjFrame.resultText:SetText(GC_L("LOC_0881") .. bjFrame.currentBet .. GC_L("LOC_0882"))
            UpdatePlayChips(bjFrame.currentBet) 
        end
    end
    bjFrame.hitBtn:SetScript("OnClick", function() table.insert(bjFrame.playerHand, table.remove(bjFrame.deck)); bjFrame.UpdateCardVisuals(); local pTotal = GetHandValue(bjFrame.playerHand); bjFrame.playerText:SetText(GC_L("LOC_0884") .. pTotal); if pTotal > 21 then EndBlackjack() end end)
    bjFrame.standBtn:SetScript("OnClick", function() EndBlackjack() end)
    bjFrame.startBtn:SetScript("OnClick", function()
        local betAmount = tonumber(bjFrame.betInput:GetText()) or 0
        if betAmount <= 0 then bjFrame.resultText:SetText(GC_L("LOC_0887")); return end; if playChips < betAmount then bjFrame.resultText:SetText(GC_L("LOC_0888")); return end
        bjFrame.currentBet = betAmount; UpdatePlayChips(-bjFrame.currentBet); bjFrame.deck, bjFrame.playerHand, bjFrame.dealerHand = CreateDeck(), {}, {}; table.insert(bjFrame.playerHand, table.remove(bjFrame.deck)); table.insert(bjFrame.dealerHand, table.remove(bjFrame.deck)); table.insert(bjFrame.playerHand, table.remove(bjFrame.deck)); bjFrame.UpdateCardVisuals() 
        local pTotal = GetHandValue(bjFrame.playerHand); bjFrame.playerText:SetText(GC_L("LOC_0889") .. pTotal); bjFrame.dealerText:SetText(GC_L("LOC_0890") .. bjFrame.dealerHand[1].value); bjFrame.resultText:SetText(GC_L("LOC_0891") .. bjFrame.currentBet .. ")"); bjFrame.hitBtn:Enable(); bjFrame.standBtn:Enable(); bjFrame.startBtn:Disable(); bjFrame.betInput:Disable(); if pTotal == 21 then EndBlackjack() end
    end)
end

local scratchFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay)
scratchFrame:SetSize(260, 445)
scratchFrame:SetPoint("CENTER", playgroundPanel.gameOverlay, "CENTER", 0, 30)
scratchFrame:Hide()

local scratchBuyBtn = CreateLocalizedButton(playgroundPanel.gameOverlay, "LOC_0896", 220, 40)
scratchBuyBtn:SetPoint("BOTTOM", playgroundPanel.gameOverlay, "BOTTOM", 0, 40)
scratchBuyBtn:Hide()

local scratchResult = playgroundPanel.gameOverlay:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
scratchResult:SetPoint("BOTTOM", scratchBuyBtn, "TOP", 0, 10)
SetCustomFont(scratchResult, 20, "OUTLINE")
scratchResult:Hide()

do
    scratchFrame.bg = scratchFrame:CreateTexture(nil, "BACKGROUND")
    scratchFrame.bg:SetAllPoints()
    scratchFrame.bg:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\sorsjegy.tga")

    scratchFrame.isActive = false
    scratchFrame.dNum = 0
    scratchFrame.pNums = {0,0,0,0}
    scratchFrame.bNums = {0,0,0}

    local function CreateScratchSurface(parent, w, h, x, y, rows, cols)
        local container = CreateFrame("Frame", nil, parent)
        container:SetSize(w, h)
        container:SetPoint("CENTER", parent, "CENTER", x, y)
        container.numBg = container:CreateTexture(nil, "BACKGROUND")
        container.numBg:SetAllPoints()
        container.numBg:SetColorTexture(0.917, 0.921, 0.929, 1) 
        container.valText = container:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
        container.valText:SetPoint("CENTER", 0, 0)
        SetCustomFont(container.valText, 24)
        
        container.pixels = {}
        container.scratchedCount = 0
        container.totalPixels = rows * cols
        container.isDone = false

        local pW, pH = w/cols, h/rows
        for r = 1, rows do
            for c = 1, cols do
                local p = container:CreateTexture(nil, "OVERLAY")
                p:SetSize(pW + 2, pH + 2)
                p:SetPoint("TOPLEFT", container, "TOPLEFT", (c-1)*pW, -(r-1)*pH)
                p:SetColorTexture(0.6, 0.6, 0.6, 1)
                table.insert(container.pixels, p)
            end
        end

        container:SetScript("OnUpdate", function(self)
            if not scratchFrame.isActive or self.isDone or not IsMouseButtonDown("LeftButton") then return end
            
            if UIFrame:IsMovable() then UIFrame:SetMovable(false) end
            
            local cx, cy = GetCursorPosition()
            local s = self:GetEffectiveScale()
            cx, cy = cx/s, cy/s
            
            local left, bottom, width, height = self:GetRect()
            if cx > left and cx < left+width and cy > bottom and cy < bottom+height then
                local hit = false
                for _, p in ipairs(self.pixels) do
                    if p:IsShown() then
                        local px, py = p:GetCenter()
                        if math.abs(cx - px) < 7 and math.abs(cy - py) < 7 then
                            p:Hide()
                            self.scratchedCount = self.scratchedCount + 1
                            hit = true
                        end
                    end
                end
                
                if hit and self.scratchedCount % 5 == 0 then
                    PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\scratch.mp3")
                end

                if (self.scratchedCount / self.totalPixels) > 0.60 then
                    self.isDone = true
                    for _, p in ipairs(self.pixels) do p:Hide() end
                    scratchFrame.CheckStatus()
                end
            end
        end)
        
        return container
    end

    scratchFrame.surfD = CreateScratchSurface(scratchFrame, 55, 45, -5, 9, 8, 8)
    scratchFrame.surfP = {
        CreateScratchSurface(scratchFrame, 50, 40, -88, 18, 8, 8),
        CreateScratchSurface(scratchFrame, 50, 40, -70, -70, 8, 8),
        CreateScratchSurface(scratchFrame, 50, 40, 65, -70, 8, 8),
        CreateScratchSurface(scratchFrame, 50, 40, 88, 18, 8, 8)
    }
    scratchFrame.surfB = CreateScratchSurface(scratchFrame, 95, 35, 65, -162, 6, 10)

    scratchFrame.CheckStatus = function()
        UIFrame:SetMovable(true)
        local count = 0
        if scratchFrame.surfD.isDone then count = count + 1 end
        for _, s in ipairs(scratchFrame.surfP) do if s.isDone then count = count + 1 end end
        if scratchFrame.surfB.isDone then count = count + 1 end
        
        scratchResult:SetText(GC_L("LOC_MANUAL_SCRATCHED") .. count .. "/6|r")
        
        if count == 6 and scratchFrame.isActive then
            scratchFrame.isActive = false
            scratchBuyBtn:Enable()
            
            local tw = 0
            for i=1, 4 do if scratchFrame.pNums[i] > scratchFrame.dNum then tw = tw + 50 end end
            if (scratchFrame.bNums[1] + scratchFrame.bNums[2] + scratchFrame.bNums[3]) == 21 then tw = tw + 500 end
            
            if tw > 0 then
                UpdatePlayChips(tw)
                scratchResult:SetText(GC_L("LOC_0921") .. tw .. GC_L("LOC_0922"))
                AddChipTransaction(CleanName(UnitName("player")), tw, GC_L("LOC_0924"))
                PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                AnnounceGameWin(GC_L("LOC_0925"), tw)
            else
                scratchResult:SetText(GC_L("LOC_0926"))
                AddChipTransaction(CleanName(UnitName("player")), -50, GC_L("LOC_0928"))
            end
        end
    end

    scratchBuyBtn:SetScript("OnClick", function()
        if playChips < 50 then scratchResult:SetText(GC_L("LOC_0930")); return end
        UpdatePlayChips(-50)
        scratchBuyBtn:Disable()
        scratchFrame.isActive = true
        scratchResult:SetText(GC_L("LOC_0931"))
        scratchResult:Show()

        scratchFrame.dNum = math.random(16, 20)
        scratchFrame.surfD.valText:SetText(scratchFrame.dNum)
        scratchFrame.surfD.valText:SetTextColor(0, 0, 0)
        scratchFrame.surfD.isDone = false
        for _, p in ipairs(scratchFrame.surfD.pixels) do p:Show() end
        scratchFrame.surfD.scratchedCount = 0

        for i, surf in ipairs(scratchFrame.surfP) do
            scratchFrame.pNums[i] = math.random(3, 21)
            surf.valText:SetText(scratchFrame.pNums[i])
            surf.valText:SetTextColor(math.random(1, 2) == 1 and 0.8 or 0, 0, 0)
            surf.isDone = false
            surf.scratchedCount = 0
            for _, p in ipairs(surf.pixels) do p:Show() end
        end
        scratchFrame.bNums = math.random(1, 100) <= 5 and {7, 7, 7} or {math.random(1,10), math.random(1,10), math.random(1,10)}
        scratchFrame.surfB.valText:SetText(scratchFrame.bNums[1].."+"..scratchFrame.bNums[2].."+"..scratchFrame.bNums[3])
        scratchFrame.surfB.valText:SetTextColor(0.8, 0.6, 0)
        scratchFrame.surfB.isDone = false
        scratchFrame.surfB.scratchedCount = 0
        for _, p in ipairs(scratchFrame.surfB.pixels) do p:Show() end
    end)
end

local pbFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); pbFrame:SetAllPoints(); pbFrame:Hide()
do
    pbFrame.result = pbFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    pbFrame.result:SetPoint("BOTTOM", pbFrame, "BOTTOM", 0, 95) 
    SetCustomFont(pbFrame.result, 20, "OUTLINE")
    
    pbFrame.dropBtn = CreateLocalizedButton(pbFrame, "LOC_0940", 150, 40)
    pbFrame.dropBtn:SetPoint("BOTTOM", pbFrame, "BOTTOM", 30, 45)
    
    pbFrame.betInput = CreateFrame("EditBox", nil, pbFrame, "InputBoxTemplate")
    pbFrame.betInput:SetSize(60, 30)
    pbFrame.betInput:SetPoint("RIGHT", pbFrame.dropBtn, "LEFT", -20, 0)
    pbFrame.betInput:SetAutoFocus(false)
    pbFrame.betInput:SetNumeric(true)
    pbFrame.betInput:SetText("20")
    SetCustomFont(pbFrame.betInput, 14)
    
    local pbLbl = pbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    pbLbl:SetPoint("BOTTOMLEFT", pbFrame.betInput, "TOPLEFT", 0, 2)
    SetCustomFont(pbLbl, 10)
    GC_RegisterLocalizedFontString(pbLbl, "LOC_0952")

    local ROWS = 12         
    local SPACE_X = 38
    local SPACE_Y = 32
    local START_Y = 260
    
    for r = 1, ROWS do 
        for c = 1, r do 
            local peg = pbFrame:CreateTexture(nil, "ARTWORK")
            peg:SetSize(12, 12)
            peg:SetPoint("CENTER", pbFrame, "CENTER", (c - 1 - (r - 1) / 2) * SPACE_X, START_Y - (r - 1) * SPACE_Y)
            peg:SetTexture("Interface\\Icons\\INV_Misc_Gem_Pearl_04") 
        end 
    end
    
    pbFrame.mults = {200, 40, 5, 2, 0.5, 0.2, 0, 0.2, 0.5, 2, 5, 40, 200}
    
    for c = 1, ROWS + 1 do 
        local slot = pbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        slot:SetPoint("CENTER", pbFrame, "CENTER", (c - 1 - ROWS / 2) * SPACE_X, START_Y - ROWS * SPACE_Y - 15)
        SetCustomFont(slot, 12, "OUTLINE")
        slot:SetText(pbFrame.mults[c] .. "x")
        
        if pbFrame.mults[c] >= 200 then slot:SetTextColor(1, 0, 1) 
        elseif pbFrame.mults[c] >= 40 then slot:SetTextColor(1, 0.5, 0) 
        elseif pbFrame.mults[c] >= 5 then slot:SetTextColor(1, 0.8, 0) 
        elseif pbFrame.mults[c] >= 2 then slot:SetTextColor(0, 1, 0) 
        elseif pbFrame.mults[c] == 0 then slot:SetTextColor(1, 0, 0) 
        else slot:SetTextColor(0.6, 0.6, 0.6) end 
    end
    
    pbFrame.ball = pbFrame:CreateTexture(nil, "OVERLAY")
    pbFrame.ball:SetSize(22, 22)
    pbFrame.ball:SetTexture("Interface\\Icons\\INV_Misc_Orb_05")
    pbFrame.ball:Hide()
    pbFrame.isDropping = false
    
    pbFrame.dropBtn:SetScript("OnClick", function()
        if pbFrame.isDropping then return end
        local betAmount = tonumber(pbFrame.betInput:GetText()) or 20
        if betAmount <= 0 then pbFrame.result:SetText(GC_L("LOC_0966")); return end
        if playChips < betAmount then pbFrame.result:SetText(GC_L("LOC_0967")); return end
        
        UpdatePlayChips(-betAmount)
        pbFrame.isDropping = true
        pbFrame.dropBtn:Disable()
        pbFrame.betInput:Disable()
        
        pbFrame.result:SetText(GC_L("LOC_0968") .. betAmount .. ")|r")
        pbFrame.ball:Show()
        
        local path, c = {{x = 0, y = START_Y + 30}}, 1
        for r = 1, ROWS do 
            table.insert(path, {x=((c - 1 - (r - 1) / 2) * SPACE_X), y=(START_Y - (r - 1) * SPACE_Y)})
            c = c + math.random(0, 1) 
        end
        table.insert(path, {x=((c - 1 - ROWS / 2) * SPACE_X), y=(START_Y - ROWS * SPACE_Y), mult = pbFrame.mults[c]})
        
        local step = 1
        pbFrame.ball:SetPoint("CENTER", pbFrame, "CENTER", path[1].x, path[1].y)
        
        C_Timer.NewTicker(0.15, function()
            step = step + 1
            if step <= #path then 
                pbFrame.ball:SetPoint("CENTER", pbFrame, "CENTER", path[step].x, path[step].y)
                if step == #path then 
                    pbFrame.isDropping = false
                    pbFrame.dropBtn:Enable()
                    pbFrame.betInput:Enable()
                    
                    local mult = path[step].mult
                    local win = math.floor(betAmount * mult)
                    
                    if win > 0 then 
                        UpdatePlayChips(win)
                        AddChipTransaction(CleanName(UnitName("player")), win, "Pachinko")
                        if mult >= 200 then
                            pbFrame.result:SetText("|cFFFF00FFEPIC JACKPOT!!! +" .. win .. "|r")
                            PlayCasinoSound(8440)
                        elseif mult >= 40 then
                            pbFrame.result:SetText("|cFFFF8000LEGENDARY! +" .. win .. "|r")
                            PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                        else
                            pbFrame.result:SetText(GC_L("LOC_0980") .. win .. " (" .. mult .. "x)|r")
                        end
                        if mult >= 40 then AnnounceGameWin("Pachinko ("..mult.."x)", win) end
                    else 
                        pbFrame.result:SetText(GC_L("LOC_0985")) 
                        AddChipTransaction(CleanName(UnitName("player")), -betAmount, "Pachinko")
                    end
                end 
            end
        end, #path - 1)
    end)
end

local pokerFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay)
pokerFrame:SetAllPoints()
pokerFrame:Hide()
do
    pokerFrame.title = pokerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    pokerFrame.title:SetPoint("TOP", 0, -90)
    SetCustomFont(pokerFrame.title, 20, "OUTLINE")
    pokerFrame.title:SetText(GC_L("LOC_0993"))

    pokerFrame.statusText = pokerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    pokerFrame.statusText:SetPoint("TOP", pokerFrame.title, "BOTTOM", 0, -5)
    SetCustomFont(pokerFrame.statusText, 14, "OUTLINE")
    pokerFrame.statusText:SetText(GC_L("LOC_0999"))
    pokerFrame.helpBtn = CreateFrame("Button", nil, pokerFrame)
    pokerFrame.helpBtn:SetSize(30, 30)
    pokerFrame.helpBtn:SetPoint("LEFT", pokerFrame.title, "RIGHT", 10, 0)  
    pokerFrame.helpBtn.tex = pokerFrame.helpBtn:CreateTexture(nil, "BACKGROUND")
    pokerFrame.helpBtn.tex:SetAllPoints()
    pokerFrame.helpBtn.tex:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    pokerFrame.helpWindow = CreateFrame("Frame", nil, pokerFrame, "BackdropTemplate")
    pokerFrame.helpWindow:SetSize(380, 520)
    pokerFrame.helpWindow:SetPoint("TOPLEFT", pokerFrame.helpBtn, "BOTTOMRIGHT", 10, 0)
    pokerFrame.helpWindow:SetFrameStrata("TOOLTIP")
    pokerFrame.helpWindow:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = {left = 4, right = 4, top = 4, bottom = 4}})
    pokerFrame.helpWindow:SetBackdropColor(0.05, 0.05, 0.05, 0.98)
    pokerFrame.helpWindow:Hide()
    local hwTitle = pokerFrame.helpWindow:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    hwTitle:SetPoint("TOP", 0, -15)
    SetCustomFont(hwTitle, 16, "OUTLINE")
    hwTitle:SetText(GC_L("LOC_1016"))
    local handsData = {
        {name="1. Royal Flush", desc=GC_L("LOC_1018"), color={1, 0.2, 1}, cards={"AH","KH","QH","JH","10H"}},
        {name=GC_L("LOC_1024"), desc=GC_L("LOC_1025"), color={1, 0.5, 0}, cards={"9S","8S","7S","6S","5S"}},
        {name=GC_L("LOC_1031"), desc=GC_L("LOC_1032"), color={1, 0.8, 0}, cards={"8C","8D","8H","8S","KD"}},
        {name="4. Full House", desc=GC_L("LOC_1039"), color={0.2, 1, 0.2}, cards={"QC","QD","QH","4S","4C"}},
        {name=GC_L("LOC_1045"), desc=GC_L("LOC_1046"), color={0.2, 0.8, 1}, cards={"AD","JD","8D","5D","2D"}},
        {name=GC_L("LOC_1052"), desc=GC_L("LOC_1053"), color={0, 1, 1}, cards={"7H","6C","5S","4D","3H"}},
        {name=GC_L("LOC_1059"), desc=GC_L("LOC_1060"), color={1, 1, 0}, cards={"10C","10S","10H","7D","2C"}},
        {name=GC_L("LOC_1066"), desc=GC_L("LOC_1067"), color={1, 0.5, 0.5}, cards={"JC","JH","9S","9D","4H"}},
        {name=GC_L("LOC_1073"), desc=GC_L("LOC_1074"), color={0.8, 0.8, 0.8}, cards={"6H","6C","KS","8D","3C"}},
        {name=GC_L("LOC_1080"), desc=GC_L("LOC_1081"), color={0.5, 0.5, 0.5}, cards={"AS","JC","9H","5D","2C"}}
    }

    for i, data in ipairs(handsData) do
        local yOffset = -50 - ((i-1) * 45)

        local text = pokerFrame.helpWindow:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        text:SetPoint("TOPLEFT", 15, yOffset)
        SetCustomFont(text, 12, "OUTLINE")
        text:SetTextColor(unpack(data.color))
        text:SetText(data.name)
        
        local subText = pokerFrame.helpWindow:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        subText:SetPoint("TOPLEFT", 15, yOffset - 15)
        SetCustomFont(subText, 10)
        subText:SetText(data.desc)

        for j, card in ipairs(data.cards) do
            local tex = pokerFrame.helpWindow:CreateTexture(nil, "ARTWORK")
            tex:SetSize(20, 40)
            tex:SetPoint("TOPRIGHT", -15 - ((5-j)*25), yOffset + 5)
            tex:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. card .. ".tga")
        end
    end

    pokerFrame.helpBtn:SetScript("OnEnter", function(self)
        pokerFrame.helpWindow:Show()
    end)
    pokerFrame.helpBtn:SetScript("OnLeave", function() 
        pokerFrame.helpWindow:Hide() 
    end)

    pokerFrame.tableBg = pokerFrame:CreateTexture(nil, "BACKGROUND")
    pokerFrame.tableBg:SetSize(450, 220) 
    pokerFrame.tableBg:SetPoint("CENTER", 0, 30)
    pokerFrame.tableBg:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\pokertable.tga")
    
    pokerFrame.potCoinGroup = CreateFrame("Frame", nil, pokerFrame)
    pokerFrame.potCoinGroup:SetSize(32, 32)
    pokerFrame.potCoinGroup:SetPoint("CENTER", pokerFrame.tableBg, "CENTER", 0, 40)
    
    local pcTex = pokerFrame.potCoinGroup:CreateTexture(nil, "BACKGROUND")
    pcTex:SetAllPoints()
    pcTex:SetTexture("Interface\\Icons\\INV_Misc_Coin_02")
    
    local pcBg = pokerFrame.potCoinGroup:CreateTexture(nil, "BORDER")
    pcBg:SetPoint("CENTER", 0, 0)
    pcBg:SetSize(60, 18)
    pcBg:SetColorTexture(0, 0, 0, 0.8)
    
    pokerFrame.potText = pokerFrame.potCoinGroup:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    pokerFrame.potText:SetPoint("CENTER", 0, 0)
    SetCustomFont(pokerFrame.potText, 14, "OUTLINE")
    pokerFrame.potText:SetTextColor(1, 0.8, 0)
    pokerFrame.potText:SetText("0")

    local chipPool = {}
    local function GetChipFromPool()
        for _, chip in ipairs(chipPool) do
            if not chip:IsShown() and not chip.isAnimating then return chip end
        end
        local chip = pokerFrame:CreateTexture(nil, "OVERLAY")
        chip:SetSize(18, 18)
        chip:SetTexture("Interface\\Icons\\INV_Misc_Coin_02")
        
        local animGroup = chip:CreateAnimationGroup()
        local trans = animGroup:CreateAnimation("Translation")
        trans:SetDuration(0.3)
        trans:SetSmoothing("OUT")
        chip.animGroup = animGroup
        chip.trans = trans
        
        table.insert(chipPool, chip)
        return chip
    end
    
    local function PlayChipAnim(startFrame, endFrame, count)
        if not startFrame or not endFrame then return end
        count = count or 1
        for j=1, count do
            C_Timer.After((j-1)*0.15, function()
                local chip = GetChipFromPool()
                chip.isAnimating = true
                chip:ClearAllPoints()
                chip:SetPoint("CENTER", startFrame, "CENTER")
                chip:Show()
                
                local sX, sY = startFrame:GetCenter()
                local eX, eY = endFrame:GetCenter()
                if sX and eX then
                    local scale = chip:GetEffectiveScale()
                    chip.trans:SetOffset((eX - sX)/scale, (eY - sY)/scale)
                    chip.animGroup:SetScript("OnFinished", function()
                        chip.isAnimating = false
                        chip:Hide()
                        PlaySound(856)
                    end)
                    chip.animGroup:Play()
                else
                    chip.isAnimating = false
                    chip:Hide()
                end
            end)
        end
    end

    pokerFrame.commCards = {}
    for i = 1, 5 do 
        local tex = pokerFrame:CreateTexture(nil, "ARTWORK")
        tex:SetSize(45, 90)
        tex:SetPoint("CENTER", pokerFrame.tableBg, "CENTER", -150 + (i*50), -20)
        tex:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        tex:Hide()
        pokerFrame.commCards[i] = tex 
    end

    pokerFrame.myCard1 = pokerFrame:CreateTexture(nil, "ARTWORK")
    pokerFrame.myCard1:SetSize(55, 110)
    pokerFrame.myCard1:SetPoint("BOTTOM", -30, 80)
    pokerFrame.myCard1:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    pokerFrame.myCard1:Hide()

    pokerFrame.myCard2 = pokerFrame:CreateTexture(nil, "ARTWORK")
    pokerFrame.myCard2:SetSize(55, 110)
    pokerFrame.myCard2:SetPoint("BOTTOM", 30, 80)
    pokerFrame.myCard2:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    pokerFrame.myCard2:Hide()

    pokerFrame.seats = {}
    local seatPos = { 
        {"TOP", -120, 25},     {"TOP", 120, 25},
        {"RIGHT", 30, 45},     {"RIGHT", 30, -45},
        {"BOTTOM", 120, -25},  {"BOTTOM", -120, -25},
        {"LEFT", -30, -45},    {"LEFT", -30, 45}
    }
    for i = 1, 8 do
        local sf = CreateFrame("Frame", nil, pokerFrame) 
        sf:SetSize(80, 50)
        sf:SetPoint(seatPos[i][1], pokerFrame.tableBg, seatPos[i][1], seatPos[i][2], seatPos[i][3])
        
        sf.bg = sf:CreateTexture(nil, "BACKGROUND")
        sf.bg:SetAllPoints()
        sf.bg:SetColorTexture(0, 0, 0, 0.5)
        
        sf.playerName = "" 
        sf.lastKnownBet = 0
        
        sf.nameText = sf:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        sf.nameText:SetPoint("TOP", 0, -2)
        SetCustomFont(sf.nameText, 10)
        sf.nameText:SetText(GC_L("LOC_1146"))
        
        sf.betText = sf:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        sf.betText:SetPoint("CENTER", 0, 0)
        SetCustomFont(sf.betText, 10)
        sf.betText:SetText("")

        sf.bankText = sf:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        sf.bankText:SetPoint("BOTTOM", 0, 2)
        SetCustomFont(sf.bankText, 10)
        sf.bankText:SetText("")
        
        sf.card1 = sf:CreateTexture(nil, "OVERLAY")
        sf.card1:SetSize(25, 50)
        sf.card1:SetPoint("BOTTOMRIGHT", sf, "TOP", -2, 2)
        sf.card1:Hide()

        sf.card2 = sf:CreateTexture(nil, "OVERLAY")
        sf.card2:SetSize(25, 50)
        sf.card2:SetPoint("BOTTOMLEFT", sf, "TOP", 2, 2)
        sf.card2:Hide()
        
        pokerFrame.seats[i] = sf
    end

    pokerFrame.btnHost = CreateLocalizedButton(pokerFrame, "LOC_1161", 120, 30)
    pokerFrame.btnHost:SetPoint("BOTTOMLEFT", 20, 55)
    
    pokerFrame.btnJoin = CreateLocalizedButton(pokerFrame, "LOC_1163", 120, 30)
    pokerFrame.btnJoin:SetPoint("BOTTOMLEFT", 150, 55)

    pokerFrame.btnLeave = CreateLocalizedButton(pokerFrame, "LOC_1165", 120, 30)
    pokerFrame.btnLeave:SetPoint("BOTTOMLEFT", 150, 55)
    pokerFrame.btnLeave:Hide()

    pokerFrame.btnStart = CreateLocalizedButton(pokerFrame, "LOC_1167", 120, 30)
    pokerFrame.btnStart:SetPoint("BOTTOMLEFT", 280, 55)
    pokerFrame.btnStart:Disable()

    pokerFrame.actionFrame = CreateFrame("Frame", nil, pokerFrame)
    pokerFrame.actionFrame:SetSize(300, 50)
    pokerFrame.actionFrame:SetPoint("LEFT", pokerFrame.myCard2, "RIGHT", 20, 0)
    pokerFrame.actionFrame:Hide()

    pokerFrame.btnFold = CreateLocalizedButton(pokerFrame.actionFrame, "LOC_1172", 80, 30)
    pokerFrame.btnFold:SetPoint("LEFT", 0, 0)

    pokerFrame.btnCall = CreateLocalizedButton(pokerFrame.actionFrame, "LOC_1174", 100, 30)
    pokerFrame.btnCall:SetPoint("LEFT", 90, 0)
    
    pokerFrame.raiseInput = CreateFrame("EditBox", nil, pokerFrame.actionFrame, "InputBoxTemplate")
    pokerFrame.raiseInput:SetSize(40, 30)
    pokerFrame.raiseInput:SetPoint("LEFT", 200, 0)
    pokerFrame.raiseInput:SetNumeric(true)
    pokerFrame.raiseInput:SetAutoFocus(false)
    pokerFrame.raiseInput:SetText("20")
    SetCustomFont(pokerFrame.raiseInput, 12)

    pokerFrame.btnRaise = CreateLocalizedButton(pokerFrame.actionFrame, "LOC_1180", 50, 30)
    pokerFrame.btnRaise:SetPoint("LEFT", 245, 0)

    pokerFrame.isHost = false
    pokerFrame.hostName = ""
    pokerFrame.seatedPlayers = {} 
    pokerFrame.gamePhase = 0 
    pokerFrame.currentDeck = {}
    pokerFrame.commDealt = {}
    pokerFrame.commCardsData = {}
    pokerFrame.currentPot = 0
    pokerFrame.currentHighestBet = 0
    pokerFrame.activePlayerIndex = 0

    local phaseNames = {"", "Pre-Flop", "Flop", "Turn", "River", "Showdown"}
    
    local function CreateDeck() 
        local newDeck = {}
        for _, suit in ipairs({"C", "D", "H", "S"}) do 
            for val = 2, 14 do 
                local rankStr = tostring(val)
                if val == 11 then rankStr = "J" elseif val == 12 then rankStr = "Q" elseif val == 13 then rankStr = "K" elseif val == 14 then rankStr = "A" end
                table.insert(newDeck, {rank = rankStr, suit = suit, val = val, tex = rankStr..suit..".tga"}) 
            end 
        end
        for i = #newDeck, 2, -1 do local j = math.random(i); newDeck[i], newDeck[j] = newDeck[j], newDeck[i] end
        return newDeck 
    end

    local function ResetTableUI()
        for i=1,5 do 
            pokerFrame.commCards[i]:Hide() 
        end
        pokerFrame.myCard1:Hide()
        pokerFrame.myCard2:Hide()
        pokerFrame.currentPot = 0
        pokerFrame.potText:SetText("0")
        for i=1,8 do 
            pokerFrame.seats[i].playerName = ""
            pokerFrame.seats[i].nameText:SetText(GC_L("LOC_1200"))
            pokerFrame.seats[i].betText:SetText("")
            pokerFrame.seats[i].bankText:SetText("")
            pokerFrame.seats[i].bg:SetColorTexture(0,0,0,0.5) 
            pokerFrame.seats[i].card1:Hide()
            pokerFrame.seats[i].card2:Hide()
            pokerFrame.seats[i].lastKnownBet = 0
        end
        pokerFrame.actionFrame:Hide()
    end

    local function EvaluateHand(hole, comm)
        local cards = {}
        for _, c in ipairs(hole) do table.insert(cards, c) end
        for _, c in ipairs(comm) do table.insert(cards, c) end
        table.sort(cards, function(a,b) return a.val > b.val end)

        local suits, vals = {C={}, D={}, H={}, S={}}, {}
        for _, c in ipairs(cards) do
            table.insert(suits[c.suit], c)
            vals[c.val] = (vals[c.val] or 0) + 1
        end

        local flushCards = nil
        for _, sCards in pairs(suits) do if #sCards >= 5 then flushCards = sCards; break end end

        local function GetStraight(cList)
            local u = {}; for _, c in ipairs(cList) do if not u[#u] or u[#u].val ~= c.val then table.insert(u, c) end end
            if #u < 5 then return nil end
            for i=1, #u-4 do if u[i].val - u[i+4].val == 4 then return {u[i], u[i+1], u[i+2], u[i+3], u[i+4]} end end
            if u[1] and u[1].val == 14 then
                local low = {}; for i=1, #u do if u[i].val <= 5 then table.insert(low, u[i]) end end
                if #low >= 4 and low[1].val==5 and low[4].val==2 then return {low[1], low[2], low[3], low[4], u[1]} end
            end
            return nil
        end

        local isStrFlush = flushCards and GetStraight(flushCards)
        if isStrFlush then 
            if isStrFlush[1].val == 14 then return 90000000000, "ROYAL FLUSH!!!" else return 80000000000 + isStrFlush[1].val*100000000, GC_L("LOC_1204") end
        end

        local groups = {}; for v, count in pairs(vals) do table.insert(groups, {v=v, c=count}) end
        table.sort(groups, function(a,b) if a.c == b.c then return a.v > b.v else return a.c > b.c end end)

        if groups[1].c == 4 then local kicker = (groups[2].v ~= groups[1].v) and groups[2].v or groups[3].v; return 70000000000 + groups[1].v*100000000 + kicker*1000000, GC_L("LOC_1205") end
        if groups[1].c == 3 and groups[2].c >= 2 then return 60000000000 + groups[1].v*100000000 + groups[2].v*1000000, "Full House" end
        if flushCards then return 50000000000 + flushCards[1].val*100000000 + flushCards[2].val*1000000 + flushCards[3].val*10000 + flushCards[4].val*100 + flushCards[5].val, GC_L("LOC_1207") end
        local isStr = GetStraight(cards)
        if isStr then return 40000000000 + isStr[1].val*100000000, GC_L("LOC_1208") end
        if groups[1].c == 3 then local kickers = {}; for _, c in ipairs(cards) do if c.val ~= groups[1].v and #kickers < 2 then table.insert(kickers, c.val) end end; return 30000000000 + groups[1].v*100000000 + (kickers[1] or 0)*1000000 + (kickers[2] or 0)*10000, GC_L("LOC_1209") end
        if groups[1].c == 2 and groups[2].c == 2 then local kicker = 0; for _, c in ipairs(cards) do if c.val ~= groups[1].v and c.val ~= groups[2].v then kicker = c.val; break end end; return 20000000000 + groups[1].v*100000000 + groups[2].v*1000000 + kicker*10000, GC_L("LOC_1210") end
        if groups[1].c == 2 then local kickers = {}; for _, c in ipairs(cards) do if c.val ~= groups[1].v and #kickers < 3 then table.insert(kickers, c.val) end end; return 10000000000 + groups[1].v*100000000 + (kickers[1] or 0)*1000000 + (kickers[2] or 0)*10000 + (kickers[3] or 0)*100, GC_L("LOC_1211") end

        return cards[1].val*100000000 + cards[2].val*1000000 + cards[3].val*10000 + cards[4].val*100 + cards[5].val, GC_L("LOC_1212")
    end

    local function BroadcastState()
        if not pokerFrame.isHost then return end
        local activeName = pokerFrame.seatedPlayers[pokerFrame.activePlayerIndex] and pokerFrame.seatedPlayers[pokerFrame.activePlayerIndex].name or ""
        local syncStr = pokerFrame.currentPot .. ":" .. pokerFrame.gamePhase .. ":" .. activeName .. ":" .. pokerFrame.currentHighestBet
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SYNC:" .. syncStr, "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "SYNC", syncStr)

        local pStates = {}
        for _, p in ipairs(pokerFrame.seatedPlayers) do 
            table.insert(pStates, p.name .. "," .. p.bet .. "," .. (p.folded and "1" or "0") .. "," .. (p.isAllIn and "1" or "0")) 
        end
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_PSTATE:" .. table.concat(pStates, "|"), "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "PSTATE", table.concat(pStates, "|"))
    end
	local function BroadcastFullPokerState(requesterName)
        if not pokerFrame.isHost then return end
        
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_HOST:"..pokerFrame.hostName, "GUILD")
        
        local seatList = ""; for _, p in ipairs(pokerFrame.seatedPlayers) do seatList = seatList .. p.name .. "," end
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SEATS:"..seatList, "GUILD")
        
        if pokerFrame.gamePhase > 0 then
            BroadcastState()
            
            if #pokerFrame.commDealt > 0 then
                C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_COMM:"..table.concat(pokerFrame.commDealt, ","), "GUILD")
            end
            
            if requesterName then
                for _, p in ipairs(pokerFrame.seatedPlayers) do
                    if p.name == requesterName and p.holeCards then
                        local payload = p.name .. ":" .. p.holeCards[1].tex .. ":" .. p.holeCards[2].tex
                        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_HOLE:" .. payload, "GUILD")
                    end
                end
            end
        end
    end

    local function EvaluateShowdown(earlyWin)
        pokerFrame.gamePhase = 0
        pokerFrame.btnStart:Enable()
        pokerFrame.btnStart:SetText(GC_L("LOC_1253"))

        local winners = {}
        local winningHandStr = GC_L("LOC_1254")
        local revealList = {} 
        
        if earlyWin then
            for _, p in ipairs(pokerFrame.seatedPlayers) do
                if not p.folded then table.insert(winners, p.name) end
            end
        else
            local bestScore = -1
            for _, p in ipairs(pokerFrame.seatedPlayers) do
                if not p.folded and p.holeCards then
                    table.insert(revealList, p.name .. "=" .. p.holeCards[1].tex .. ":" .. p.holeCards[2].tex)
                    local score, handStr = EvaluateHand(p.holeCards, pokerFrame.commCardsData)
                    if score > bestScore then
                        bestScore = score
                        winners = {p.name}
                        winningHandStr = handStr
                    elseif score == bestScore then
                        table.insert(winners, p.name)
                    end
                end
            end
        end

        local winAmt = math.floor(pokerFrame.currentPot / #winners)
        local winnerStr = table.concat(winners, GC_L("LOC_1257"))
        local msg = GC_L("LOC_1258") .. winnerStr .. GC_L("LOC_1259") .. winningHandStr .. ")!"
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SYS:"..msg, "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "SYS", msg)
        
        if winAmt > 0 then
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_PAY:" .. table.concat(winners, ",") .. ":" .. winAmt, "GUILD")
            _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "PAY", table.concat(winners, ",") .. ":" .. winAmt)
        end

        if #revealList > 0 then
            local revealStr = table.concat(revealList, "|")
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_REVEAL:" .. revealStr, "GUILD")
            _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "REVEAL", revealStr)
        end
    end

    local function AdvanceTurn()
        if not pokerFrame.isHost or pokerFrame.gamePhase == 0 then return end

        local notFoldedCount = 0
        local canActCount = 0
        for _, p in ipairs(pokerFrame.seatedPlayers) do 
            if not p.folded then 
                notFoldedCount = notFoldedCount + 1 
                if not p.isAllIn then canActCount = canActCount + 1 end
            end 
        end
        
        if notFoldedCount <= 1 then
            EvaluateShowdown(true)
            return
        end

        local allActed = true
        local allMatched = true
        for _, p in ipairs(pokerFrame.seatedPlayers) do
            if not p.folded and not p.isAllIn then
                if not p.acted then allActed = false end
                if p.bet < pokerFrame.currentHighestBet then allMatched = false end
            end
        end

        if allActed and allMatched then
            pokerFrame.gamePhase = pokerFrame.gamePhase + 1
            pokerFrame.currentHighestBet = 0
            for _, p in ipairs(pokerFrame.seatedPlayers) do
                if not p.isAllIn then
                    p.bet = 0
                    p.acted = false
                end
            end

            if pokerFrame.gamePhase == 2 then
                local c1, c2, c3 = table.remove(pokerFrame.currentDeck), table.remove(pokerFrame.currentDeck), table.remove(pokerFrame.currentDeck)
                table.insert(pokerFrame.commCardsData, c1); table.insert(pokerFrame.commCardsData, c2); table.insert(pokerFrame.commCardsData, c3)
                table.insert(pokerFrame.commDealt, c1.tex); table.insert(pokerFrame.commDealt, c2.tex); table.insert(pokerFrame.commDealt, c3.tex)
            elseif pokerFrame.gamePhase == 3 or pokerFrame.gamePhase == 4 then
                local c = table.remove(pokerFrame.currentDeck)
                table.insert(pokerFrame.commCardsData, c); table.insert(pokerFrame.commDealt, c.tex)
            elseif pokerFrame.gamePhase == 5 then
                EvaluateShowdown(false)
                return
            end

            if pokerFrame.gamePhase >= 2 and pokerFrame.gamePhase <= 4 then
                local payload = table.concat(pokerFrame.commDealt, ",")
                C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_COMM:"..payload, "GUILD")
                _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "COMM", payload)
            end

            pokerFrame.activePlayerIndex = 0
        end

        if canActCount > 0 or (allActed and allMatched and pokerFrame.gamePhase < 5) then
            if canActCount > 0 then
                local startIdx = pokerFrame.activePlayerIndex
                repeat
                    pokerFrame.activePlayerIndex = pokerFrame.activePlayerIndex + 1
                    if pokerFrame.activePlayerIndex > #pokerFrame.seatedPlayers then pokerFrame.activePlayerIndex = 1 end
                    local cp = pokerFrame.seatedPlayers[pokerFrame.activePlayerIndex]
                    if not cp.folded and not cp.isAllIn then break end
                    if pokerFrame.activePlayerIndex == startIdx then break end
                until false
            end
            BroadcastState()
            
            if canActCount == 0 and pokerFrame.gamePhase < 5 then
                C_Timer.After(1, AdvanceTurn)
            end
        end
    end

    pokerFrame.btnHost:SetScript("OnClick", function()
        if pokerFrame.isHost then
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_CLOSE:1", "GUILD")
            _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "CLOSE", "1")
        else
            if pokerFrame.hostName ~= "" then print(GC_L("LOC_1295")); return end
            if not IsInGuild() then print(GC_L("LOC_1296")); return end
            pokerFrame.isHost = true
            pokerFrame.hostName = CleanName(UnitName("player"))
            pokerFrame.btnHost:SetText(GC_L("LOC_1298"))
            pokerFrame.btnJoin:Disable()
            pokerFrame.btnLeave:Hide()
            
            pokerFrame.seatedPlayers = { {name=pokerFrame.hostName, bet=0, folded=false, acted=false, isAllIn=false} }
            
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_HOST:"..pokerFrame.hostName, "GUILD")
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SEATS:"..pokerFrame.hostName..",", "GUILD")
            _G.GuildCasino_PokerMsg(pokerFrame.hostName, "SEATS", pokerFrame.hostName..",")

            pokerFrame.statusText:SetText(GC_L("LOC_1308"))
            pokerFrame.btnStart:Enable()
        end
    end)

    pokerFrame.btnJoin:SetScript("OnClick", function()
        if pokerFrame.hostName == "" then return end
        if playChips < 100 then print(GC_L("LOC_1311")); return end
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_JOIN:"..CleanName(UnitName("player")), "GUILD")
        pokerFrame.btnJoin:Hide()
        pokerFrame.btnLeave:Show()
    end)

    pokerFrame.btnLeave:SetScript("OnClick", function()
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_LEAVE:"..CleanName(UnitName("player")), "GUILD")
        pokerFrame.btnLeave:Hide()
        pokerFrame.btnJoin:Show()
        
        pokerFrame.actionFrame:Hide()
        pokerFrame.myCard1:Hide()
        pokerFrame.myCard2:Hide()
    end)

    pokerFrame.btnStart:SetScript("OnClick", function()
        if not pokerFrame.isHost or #pokerFrame.seatedPlayers < 2 then return end
        pokerFrame.btnStart:Disable()
        pokerFrame.btnStart:SetText(GC_L("LOC_1322"))
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_RESET:1", "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "RESET", "1")

        pokerFrame.gamePhase = 1
        pokerFrame.currentPot = 0
        pokerFrame.currentHighestBet = 0
        pokerFrame.currentDeck = CreateDeck()
        pokerFrame.commDealt = {}
        pokerFrame.commCardsData = {}
        
        for _, p in ipairs(pokerFrame.seatedPlayers) do
            p.bet = 0
            p.folded = false
            p.acted = false
            p.isAllIn = false 
            local c1, c2 = table.remove(pokerFrame.currentDeck), table.remove(pokerFrame.currentDeck)
            p.holeCards = {c1, c2}
            
            local payload = p.name .. ":" .. c1.tex .. ":" .. c2.tex
            C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_HOLE:" .. payload, "GUILD")
            
            if p.name == CleanName(UnitName("player")) then 
                _G.GuildCasino_PokerMsg(p.name, "HOLE", payload) 
            end
        end

        pokerFrame.activePlayerIndex = 0
        AdvanceTurn()
    end)

    local function GetMySeatInfo()
        local myName = CleanName(UnitName("player"))
        for i, p in ipairs(pokerFrame.seatedPlayers) do if p.name == myName then return p end end
        return nil
    end

    pokerFrame.btnFold:SetScript("OnClick", function()
        pokerFrame.actionFrame:Hide()
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_ACT:FOLD:0", "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "ACT", "FOLD:0")
    end)
    
    pokerFrame.btnCall:SetScript("OnClick", function()
        local me = GetMySeatInfo()
        if not me then return end
        local toCall = pokerFrame.currentHighestBet - me.bet
        local isAllIn = false
        
        if toCall > 0 and playChips <= toCall then
            toCall = playChips
            isAllIn = true
            print(GC_L("LOC_1345"))
        end
        
        pokerFrame.actionFrame:Hide()
        if toCall > 0 then UpdatePlayChips(-toCall) end
        
        local cmd = isAllIn and "ALLIN" or "CALL"
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_ACT:"..cmd..":"..toCall, "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "ACT", cmd..":"..toCall)
    end)
    
    pokerFrame.btnRaise:SetScript("OnClick", function()
        local me = GetMySeatInfo()
        if not me then return end
        local raiseAmt = tonumber(pokerFrame.raiseInput:GetText()) or 10
        local toCall = pokerFrame.currentHighestBet - me.bet
        local totalDeduct = toCall + raiseAmt
        
        if playChips < totalDeduct then 
            print(GC_L("LOC_1356"))
            return 
        end
        
        pokerFrame.actionFrame:Hide()
        UpdatePlayChips(-totalDeduct)
        
        local isAllIn = (playChips == 0)
        local cmd = isAllIn and "ALLIN" or "RAISE"
        C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_ACT:"..cmd..":"..totalDeduct, "GUILD")
        _G.GuildCasino_PokerMsg(CleanName(UnitName("player")), "ACT", cmd..":"..totalDeduct)
    end)

    _G.GuildCasino_PokerMsg = function(sender, cmd, payload)
        if cmd == "HOST" then
    local oldHost = CleanName(pokerFrame.hostName or "")
    local newHost = CleanName(payload or "")
    local wasInGame = (pokerFrame.gamePhase or 0) > 0

    pokerFrame.hostName = newHost
    pokerFrame.statusText:SetText(newHost .. GC_L("LOC_1367"))

    -- Fontos: játék közbeni state syncnél ne resetelje az asztalt,
    -- mert a ResetTableUI() elrejti a saját és közös lapokat.
    if not wasInGame or oldHost ~= newHost then
        ResetTableUI()
    end

    pokerFrame.btnHost:Disable() 
    if not pokerFrame.isHost then
        pokerFrame.btnJoin:Show()
        pokerFrame.btnJoin:Enable()
        pokerFrame.btnLeave:Hide()
    end
        elseif cmd == "CLOSE" then
            pokerFrame.hostName = ""; pokerFrame.isHost = false; pokerFrame.gamePhase = 0; pokerFrame.currentPot = 0
            pokerFrame.statusText:SetText(GC_L("LOC_1370"))
            ResetTableUI()
            pokerFrame.btnHost:Enable(); pokerFrame.btnHost:SetText(GC_L("LOC_1371"))
            pokerFrame.btnJoin:Show(); pokerFrame.btnJoin:Enable(); pokerFrame.btnLeave:Hide(); pokerFrame.btnStart:Disable(); pokerFrame.btnStart:SetText(GC_L("LOC_1372"))
        elseif cmd == "JOIN" and pokerFrame.isHost then
            local alreadySeated = false
            for _, p in ipairs(pokerFrame.seatedPlayers) do if p.name == payload then alreadySeated = true end end
            if not alreadySeated and #pokerFrame.seatedPlayers < 8 then
                table.insert(pokerFrame.seatedPlayers, {name=payload, bet=0, folded=false, acted=false, isAllIn=false})
                local seatList = ""; for _, p in ipairs(pokerFrame.seatedPlayers) do seatList = seatList .. p.name .. "," end
                C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SEATS:"..seatList, "GUILD")
                _G.GuildCasino_PokerMsg(sender, "SEATS", seatList)
                if #pokerFrame.seatedPlayers >= 2 then pokerFrame.btnStart:Enable() end
            end
        
            elseif cmd == "LEAVE" and pokerFrame.isHost then
            local removedIndex = 0
            for i, p in ipairs(pokerFrame.seatedPlayers) do
                if p.name == payload then
                    removedIndex = i
                    if pokerFrame.gamePhase > 0 and not p.folded then
                        p.folded = true
                    end
                    break
                end
            end
            
            if removedIndex > 0 then
                table.remove(pokerFrame.seatedPlayers, removedIndex)               
                if pokerFrame.activePlayerIndex >= removedIndex then
                    pokerFrame.activePlayerIndex = pokerFrame.activePlayerIndex - 1
                end
                
                local seatList = ""; for _, p in ipairs(pokerFrame.seatedPlayers) do seatList = seatList .. p.name .. "," end
                C_ChatInfo.SendAddonMessage("GUILDCASINO", "PKR_SEATS:"..seatList, "GUILD")
                _G.GuildCasino_PokerMsg(sender, "SEATS", seatList)
                
                if #pokerFrame.seatedPlayers < 2 then 
                    pokerFrame.btnStart:Disable()
                    if pokerFrame.gamePhase > 0 then
                        EvaluateShowdown(true)
                    end
                else
                    if pokerFrame.gamePhase > 0 then
                        AdvanceTurn()
                    end
                end
            end
        elseif cmd == "SEATS" then
            local seats = {strsplit(",", payload)}
            local myName = CleanName(UnitName("player"))
            local amISeated = false
            
            for i=1, 8 do
                if seats[i] and seats[i] ~= "" then 
                    local pName = CleanName(seats[i])
                    pokerFrame.seats[i].playerName = pName 
                    pokerFrame.seats[i].nameText:SetText(ColorName(pName)) 
                    if pName == myName then amISeated = true end
                    local chips = (GuildCasino_DB_V1["CHIPS"] and GuildCasino_DB_V1["CHIPS"][pName]) or 0
                    pokerFrame.seats[i].bankText:SetText(chips .. GC_L("LOC_1393"))
                    pokerFrame.seats[i].betText:SetText(GC_L("LOC_1394"))
                else 
                    pokerFrame.seats[i].playerName = ""
                    pokerFrame.seats[i].nameText:SetText(GC_L("LOC_1396")) 
                    pokerFrame.seats[i].betText:SetText("")
                    pokerFrame.seats[i].bankText:SetText("")
                end
            end
            
            if not pokerFrame.isHost and pokerFrame.hostName ~= "" then
                if amISeated then
                    pokerFrame.btnJoin:Hide(); pokerFrame.btnLeave:Show()
                else
                    pokerFrame.btnJoin:Show(); pokerFrame.btnLeave:Hide()
                end
            end
        elseif cmd == "RESET" then
            for i=1,5 do 
                pokerFrame.commCards[i]:Hide() 
            end
            for i=1,8 do
                pokerFrame.seats[i].card1:Hide()
                pokerFrame.seats[i].card2:Hide()
                pokerFrame.seats[i].bg:SetColorTexture(0,0,0,0.5)
                pokerFrame.seats[i].betText:SetText("")
                pokerFrame.seats[i].lastKnownBet = 0
            end
            pokerFrame.myCard1:Hide(); pokerFrame.myCard2:Hide(); pokerFrame.actionFrame:Hide()
            pokerFrame.currentPot = 0; pokerFrame.potText:SetText("0")
        elseif cmd == "SYNC" then
            local pot, phase, activeName, highestBet = strsplit(":", payload)
            
            local nPhase = tonumber(phase) or 0
            if nPhase ~= pokerFrame.gamePhase then
                for i=1, 8 do pokerFrame.seats[i].lastKnownBet = 0 end
            end
            
            pokerFrame.currentPot = tonumber(pot) or 0
            pokerFrame.gamePhase = nPhase
            pokerFrame.currentHighestBet = tonumber(highestBet) or 0
            pokerFrame.potText:SetText(tostring(pokerFrame.currentPot))
            
            pokerFrame.statusText:SetText("|cFFFFFF00" .. phaseNames[pokerFrame.gamePhase] .. GC_L("LOC_1406") .. activeName .. GC_L("LOC_1407"))

            local myName = CleanName(UnitName("player"))
            for i=1, 8 do
                local seatName = pokerFrame.seats[i].playerName
                if seatName and seatName ~= "" then
                    if seatName == activeName then
                        pokerFrame.seats[i].bg:SetColorTexture(0.8, 0.8, 0, 0.5) 
                    else
                        pokerFrame.seats[i].bg:SetColorTexture(0, 0, 0, 0.5) 
                    end
                end
            end

            if activeName == myName then
                PlaySound(8959) 
                local me = GetMySeatInfo()
                if me then
                    local toCall = pokerFrame.currentHighestBet - me.bet
                    pokerFrame.actionFrame:Show()
                    pokerFrame.btnFold:Enable()
                    pokerFrame.btnCall:Enable()
                    pokerFrame.btnRaise:Enable()
                    
                    if toCall == 0 then
                        pokerFrame.btnCall:SetText(GC_L("LOC_1410"))
                        pokerFrame.btnRaise:SetText(GC_L("LOC_1411"))
                    else
                        pokerFrame.btnCall:SetText(GC_L("LOC_1412")..toCall..")")
                        pokerFrame.btnRaise:SetText(GC_L("LOC_1414"))
                    end
                end
            else
                pokerFrame.actionFrame:Hide()
            end

        elseif cmd == "PSTATE" then
            local pDatas = {strsplit("|", payload)}
            for _, pStr in ipairs(pDatas) do
                if pStr and pStr ~= "" then
                    local pName, pBet, pFolded, pAllIn = strsplit(",", pStr)
                    local cBet = tonumber(pBet) or 0
                    
                    for i=1, 8 do
                        local seatName = pokerFrame.seats[i].playerName
                        if seatName == CleanName(pName) then
                            
                            if cBet > (pokerFrame.seats[i].lastKnownBet or 0) then
                                PlayChipAnim(pokerFrame.seats[i], pokerFrame.potCoinGroup, 1)
                            end
                            pokerFrame.seats[i].lastKnownBet = cBet

                            local chips = (GuildCasino_DB_V1["CHIPS"] and GuildCasino_DB_V1["CHIPS"][pName]) or 0
                            pokerFrame.seats[i].bankText:SetText(chips .. GC_L("LOC_1421"))

                            if pFolded == "1" then
                                pokerFrame.seats[i].bg:SetColorTexture(0.8, 0.1, 0.1, 0.5)
                                pokerFrame.seats[i].betText:SetText(GC_L("LOC_1423"))
                            elseif pAllIn == "1" then
                                pokerFrame.seats[i].betText:SetText("|cFFFFD100ALL-IN|r ("..cBet..")")
                            else
                                pokerFrame.seats[i].betText:SetText("|cFF00FF00" .. cBet .. GC_L("LOC_1428"))
                            end
                        end
                    end
                    
                    if not pokerFrame.isHost then
                        local found = false
                        for _, hp in ipairs(pokerFrame.seatedPlayers) do
                            if hp.name == pName then
                                hp.bet = cBet
                                hp.folded = (pFolded == "1")
                                hp.isAllIn = (pAllIn == "1")
                                found = true
                            end
                        end
                        if not found then table.insert(pokerFrame.seatedPlayers, {name=pName, bet=cBet, folded=(pFolded=="1"), isAllIn=(pAllIn=="1")}) end
                    end
                end
            end
        elseif cmd == "ACT" and pokerFrame.isHost then
            local p = pokerFrame.seatedPlayers[pokerFrame.activePlayerIndex]
            if p and p.name == sender then
                local actType, amtStr = strsplit(":", payload)
                local amt = tonumber(amtStr) or 0

                if actType == "FOLD" then
                    p.folded = true
                elseif actType == "CALL" or actType == "RAISE" or actType == "ALLIN" then
                    p.bet = p.bet + amt
                    pokerFrame.currentPot = pokerFrame.currentPot + amt
                    
                    if actType == "ALLIN" then p.isAllIn = true end
                    
                    if p.bet > pokerFrame.currentHighestBet then
                        pokerFrame.currentHighestBet = p.bet
                        for _, other in ipairs(pokerFrame.seatedPlayers) do
                            if not other.folded and not other.isAllIn and other.name ~= p.name then
                                other.acted = false
                            end
                        end
                    end
                end
                p.acted = true
                AdvanceTurn()
            end
        elseif cmd == "COMM" then
            local cards = {strsplit(",", payload)}
            for i=1, 5 do
                if cards[i] and cards[i] ~= "" then
                    pokerFrame.commCards[i]:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. cards[i])
                    pokerFrame.commCards[i]:Show()
                else
                    pokerFrame.commCards[i]:Hide()
                end
            end
            PlaySound(856)
        elseif cmd == "HOLE" then
            local targetName, c1, c2 = strsplit(":", payload)
            
            if targetName == CleanName(UnitName("player")) then
                pokerFrame.myCard1:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. c1)
                pokerFrame.myCard1:Show()
                pokerFrame.myCard2:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. c2)
                pokerFrame.myCard2:Show()
                PlaySound(856)
            end
        elseif cmd == "REVEAL" then
            local players = {strsplit("|", payload)}
            for _, pData in ipairs(players) do
                if pData and pData ~= "" then
                    local pName, cardsStr = strsplit("=", pData)
                    local c1, c2 = strsplit(":", cardsStr)
                    for i=1, 8 do
                        if pokerFrame.seats[i].playerName == pName then
                            pokerFrame.seats[i].card1:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. c1)
                            pokerFrame.seats[i].card1:Show()
                            pokerFrame.seats[i].card2:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\" .. c2)
                            pokerFrame.seats[i].card2:Show()
                        end
                    end
                end
            end
        elseif cmd == "PAY" then
            local winnersStr, amtStr = strsplit(":", payload)
            local winners = {strsplit(",", winnersStr)}
            local winAmt = tonumber(amtStr) or 0
            local myName = CleanName(UnitName("player"))
            for _, w in ipairs(winners) do
                local cleanW = CleanName(w)
                
                for i=1, 8 do
                    if pokerFrame.seats[i].playerName == cleanW then
                        PlayChipAnim(pokerFrame.potCoinGroup, pokerFrame.seats[i], 3)
                    end
                end
                
                if cleanW == myName then
                    UpdatePlayChips(winAmt)
					AddChipTransaction(cleanW, winAmt, GC_L("LOC_1460"))
                    print(GC_L("LOC_1461") .. winAmt .. GC_L("LOC_1462"))
                end
            end
        elseif cmd == "SYS" then
            pokerFrame.statusText:SetText("|cFFFFFF00" .. payload .. "|r")
            if string.find(payload, "SHOWDOWN") then PlaySound(8440) end 
			elseif cmd == "REQ_STATE" then
            if pokerFrame.isHost then
                local requester = payload
                C_Timer.After(math.random() * 2, function() BroadcastFullPokerState(requester) end)
            end
        end
    end
end

local minesFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); minesFrame:SetAllPoints(); minesFrame:Hide()
do
    minesFrame.difficulties = {
        {bombs = 3, localeKey = "LOC_1469"},
        {bombs = 5, localeKey = "LOC_1470"},
        {bombs = 10, localeKey = "LOC_1471"},
        {bombs = 15, localeKey = "LOC_1472"}
    }
    minesFrame.currentDiffIdx = 2
    minesFrame.bombCount = 5

    local function GetMinesDifficultyName()
        return GC_L(minesFrame.difficulties[minesFrame.currentDiffIdx].localeKey)
    end

    local function UpdateMinesDifficultyButton()
        if minesFrame.diffBtn then
            minesFrame.diffBtn:SetText(GC_L("LOC_MANUAL_LEVEL_PREFIX") .. GetMinesDifficultyName())
        end
    end

    minesFrame.result = minesFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); minesFrame.result:SetPoint("TOP", minesFrame, "TOP", 0, -65); SetCustomFont(minesFrame.result, 18, "OUTLINE"); minesFrame.result:SetText(GC_L("LOC_1478") .. minesFrame.bombCount .. GC_L("LOC_1479"))
    minesFrame.currentWinStr = minesFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); minesFrame.currentWinStr:SetPoint("TOP", minesFrame.result, "BOTTOM", 0, -5); SetCustomFont(minesFrame.currentWinStr, 14, "OUTLINE"); minesFrame.currentWinStr:SetText(GC_L("LOC_1485"))
    minesFrame.tiles, minesFrame.bombs, minesFrame.safeClicks, minesFrame.isActive = {}, {}, 0, false
    
    minesFrame.grid = CreateFrame("Frame", nil, minesFrame); minesFrame.grid:SetSize(200, 200); minesFrame.grid:SetPoint("CENTER", minesFrame, "CENTER", 0, 15)
    minesFrame.startBtn = CreateLocalizedButton(minesFrame, "LOC_1489", 120, 35); minesFrame.startBtn:SetPoint("BOTTOMLEFT", minesFrame, "BOTTOMLEFT", 60, 40)   
    minesFrame.diffBtn = CreateModernButton(minesFrame, "", 140, 35)
    minesFrame.diffBtn:SetPoint("BOTTOM", minesFrame, "BOTTOM", 0, 40)   
    UpdateMinesDifficultyButton()
    minesFrame.cashoutBtn = CreateLocalizedButton(minesFrame, "LOC_1495", 120, 35); minesFrame.cashoutBtn:SetPoint("BOTTOMRIGHT", minesFrame, "BOTTOMRIGHT", -60, 40); minesFrame.cashoutBtn:Disable()
    minesFrame.diffBtn:SetScript("OnClick", function()
        minesFrame.currentDiffIdx = minesFrame.currentDiffIdx + 1
        if minesFrame.currentDiffIdx > #minesFrame.difficulties then minesFrame.currentDiffIdx = 1 end       
        minesFrame.bombCount = minesFrame.difficulties[minesFrame.currentDiffIdx].bombs
        UpdateMinesDifficultyButton()
        minesFrame.result:SetText(GC_L("LOC_1500") .. minesFrame.bombCount .. GC_L("LOC_1501"))
    end)
    minesFrame.RefreshLanguage = function()
        UpdateMinesDifficultyButton()
        if not minesFrame.isActive then
            minesFrame.result:SetText(GC_L("LOC_1478") .. minesFrame.bombCount .. GC_L("LOC_1479"))
            minesFrame.currentWinStr:SetText(GC_L("LOC_1485"))
        end
    end
    local function CalcMult(clicks) 
        if clicks == 0 then return 0 end
        local p = 1.0
        local safeTiles = 25 - minesFrame.bombCount
        for i = 0, clicks - 1 do 
            p = p * ((safeTiles - i) / (25 - i)) 
        end
        return math.floor((1 / p) * 0.95 * 100) / 100 
    end
    
    local function EndMines(won)
        minesFrame.isActive = false
        minesFrame.cashoutBtn:Disable()
        minesFrame.startBtn:Enable()
        minesFrame.diffBtn:Enable()
        
        for i = 1, 25 do 
            minesFrame.tiles[i].cover:Hide()
            if minesFrame.bombs[i] then 
                minesFrame.tiles[i].tex:SetTexture("Interface\\Icons\\INV_Misc_Bomb_04")
                minesFrame.tiles[i].tex:SetColorTexture(1, (not won and minesFrame.tiles[i].isClicked) and 0 or 1, (not won and minesFrame.tiles[i].isClicked) and 0 or 1, 1) 
            else 
                minesFrame.tiles[i].tex:SetTexture("Interface\\Icons\\INV_Misc_Gem_Diamond_02")
                minesFrame.tiles[i].tex:SetVertexColor(0.5, 0.5, 0.5) 
            end 
        end       
        if won then 
            local winAmt = math.floor(10 * CalcMult(minesFrame.safeClicks))
            UpdatePlayChips(winAmt)
            AddChipTransaction(CleanName(UnitName("player")), winAmt, GC_L("LOC_1505"))
            minesFrame.result:SetText(GC_L("LOC_1506") .. winAmt .. GC_L("LOC_1507"))
            PlayCasinoSound(856)
            if winAmt >= 50 then PlayCasinoSound(SOUNDKIT.RAID_WARNING) end
            AnnounceGameWin(GC_L("LOC_1508")..minesFrame.bombCount..GC_L("LOC_1509"), winAmt) 
        else 
            minesFrame.result:SetText(GC_L("LOC_1510")) 
            AddChipTransaction(CleanName(UnitName("player")), -10, GC_L("LOC_1512"))
        end
    end   
    for i = 1, 25 do
        local btn = CreateFrame("Button", nil, minesFrame.grid); btn:SetSize(38, 38); btn:SetPoint("TOPLEFT", minesFrame.grid, "TOPLEFT", ((i - 1) % 5) * 40, -math.floor((i - 1) / 5) * 40)
        btn.tex = btn:CreateTexture(nil, "ARTWORK"); btn.tex:SetAllPoints(); btn.tex:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark"); btn.cover = btn:CreateTexture(nil, "OVERLAY"); btn.cover:SetAllPoints(); btn.cover:SetColorTexture(0.3, 0.3, 0.3, 1)
        local hl = btn:CreateTexture(nil, "HIGHLIGHT"); hl:SetAllPoints(); hl:SetColorTexture(1, 1, 1, 0.2); btn.isClicked = false; btn.id = i       
        btn:SetScript("OnClick", function(self) 
            if not minesFrame.isActive or self.isClicked then return end
            self.isClicked = true
            self.cover:Hide()
            
            if minesFrame.bombs[self.id] then 
                EndMines(false) 
            else 
                self.tex:SetTexture("Interface\\Icons\\INV_Misc_Gem_Diamond_02")
                self.tex:SetVertexColor(1, 1, 1)
                minesFrame.safeClicks = minesFrame.safeClicks + 1
                
                local mult = CalcMult(minesFrame.safeClicks)
                minesFrame.currentWinStr:SetText(GC_L("LOC_1522") .. math.floor(10 * mult) .. GC_L("LOC_1523") .. mult .. "x)")
                if minesFrame.safeClicks == (25 - minesFrame.bombCount) then 
                    EndMines(true) 
                end 
            end 
        end)
        minesFrame.tiles[i] = btn
    end  
    minesFrame.startBtn:SetScript("OnClick", function()
        if playChips < 10 then minesFrame.result:SetText(GC_L("LOC_1526")); return end
        UpdatePlayChips(-10)       
        minesFrame.isActive = true
        minesFrame.safeClicks = 0
        minesFrame.startBtn:Disable()
        minesFrame.cashoutBtn:Enable()
        minesFrame.diffBtn:Disable()  
        minesFrame.result:SetText(GC_L("LOC_1527") .. minesFrame.bombCount .. GC_L("LOC_1528"))
        minesFrame.currentWinStr:SetText(GC_L("LOC_1529"))
        
        for i = 1, 25 do 
            minesFrame.tiles[i].isClicked = false
            minesFrame.tiles[i].cover:Show()
            minesFrame.tiles[i].tex:SetVertexColor(1, 1, 1)
            minesFrame.tiles[i].tex:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            minesFrame.tiles[i].tex:SetColorTexture(1, 1, 1, 1)
            minesFrame.bombs[i] = false 
        end
        
        local placed = 0
        while placed < minesFrame.bombCount do 
            local rnd = math.random(1, 25)
            if not minesFrame.bombs[rnd] then 
                minesFrame.bombs[rnd] = true
                placed = placed + 1 
            end 
        end
    end)
    
    minesFrame.cashoutBtn:SetScript("OnClick", function() 
        if minesFrame.isActive and minesFrame.safeClicks > 0 then EndMines(true) end 
    end)
end

local horseFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); horseFrame:SetAllPoints(); horseFrame:Hide()
do
    horseFrame.track = horseFrame:CreateTexture(nil, "BACKGROUND"); horseFrame.track:SetSize(450, 200); horseFrame.track:SetPoint("CENTER", 0, 40); horseFrame.track:SetColorTexture(0.15, 0.45, 0.15, 1)
    for i = 1, 3 do 
        local line = horseFrame:CreateTexture(nil, "BORDER"); line:SetSize(450, 2); line:SetPoint("TOP", horseFrame.track, "TOP", 0, -(i * 50)); line:SetColorTexture(1, 1, 1, 0.3) 
    end
    local startLine = horseFrame:CreateTexture(nil, "ARTWORK"); startLine:SetSize(4, 200); startLine:SetPoint("LEFT", horseFrame.track, "LEFT", 40, 0); startLine:SetColorTexture(1, 1, 1, 0.7)
    local finishLine = horseFrame:CreateTexture(nil, "ARTWORK"); finishLine:SetSize(8, 200); finishLine:SetPoint("LEFT", horseFrame.track, "LEFT", 410, 0); finishLine:SetColorTexture(0.8, 0.1, 0.1, 0.9)
    horseFrame.horses, horseFrame.isRacing, horseFrame.colors = {}, false, {{1,0.2,0.2}, {0.2,1,0.2}, {0.2,0.5,1}, {1,1,0.2}}
    for i=1,4 do 
        local h = horseFrame:CreateTexture(nil, "OVERLAY"); h:SetSize(32, 32); h:SetTexture("Interface\\Icons\\Ability_Mount_NightmareHorse"); h:SetVertexColor(unpack(horseFrame.colors[i])); h:SetPoint("CENTER", horseFrame.track, "TOPLEFT", 20, -25 - (i-1)*50); horseFrame.horses[i] = h 
    end
    
    horseFrame.msg = horseFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); horseFrame.msg:SetPoint("TOP", horseFrame.track, "BOTTOM", 0, -10); SetCustomFont(horseFrame.msg, 18, "OUTLINE"); horseFrame.msg:SetText(GC_L("LOC_1564"))
    horseFrame.betInput = CreateFrame("EditBox", nil, horseFrame, "InputBoxTemplate")
    horseFrame.betInput:SetSize(65, 30); horseFrame.betInput:SetPoint("BOTTOMLEFT", horseFrame, "BOTTOMLEFT", 20, 45)
    horseFrame.betInput:SetNumeric(true); horseFrame.betInput:SetAutoFocus(false); horseFrame.betInput:SetText("20")
    SetCustomFont(horseFrame.betInput, 14)
    local hLbl = horseFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    hLbl:SetPoint("BOTTOMLEFT", horseFrame.betInput, "TOPLEFT", 0, 2); SetCustomFont(hLbl, 10); GC_RegisterLocalizedFontString(hLbl, "LOC_1574")
    local function StartHorseRace(bet, betAmount)
        if horseFrame.isRacing then return end; horseFrame.isRacing = true; horseFrame.msg:SetText("|cFFFFFF00A VERSENY ELINDULT!|r"); PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3") 
        local pos, timerTick = {20, 20, 20, 20}, 0
        C_Timer.NewTicker(0.05, function(ticker)
            timerTick = timerTick + 1; local winner, currentLeader, maxPos = nil, 1, 0
            for i=1,4 do
                local spd, rnd = math.random(1, 6), math.random(1, 100)
                if rnd > 90 then spd = spd + math.random(8, 18) elseif rnd < 12 then spd = 0 end
                pos[i] = pos[i] + spd; horseFrame.horses[i]:SetPoint("CENTER", horseFrame.track, "TOPLEFT", pos[i], -25 - (i-1)*50)
                if pos[i] > maxPos then maxPos = pos[i]; currentLeader = i end; if pos[i] >= 410 and not winner then winner = i end
            end
            if not winner and timerTick % 10 == 0 then horseFrame.msg:SetText("A(z) |cFFFFFF00" .. currentLeader .. GC_L("LOC_1580")) end
            if winner then
                ticker:Cancel(); horseFrame.isRacing = false
                if winner == bet then 
                    local winAmt = betAmount * 4
                    UpdatePlayChips(winAmt)
                    AddChipTransaction(CleanName(UnitName("player")), winAmt, GC_L("LOC_1582"))
                    horseFrame.msg:SetText(GC_L("LOC_1583") .. winner .. GC_L("LOC_1584")..winAmt..")|r"); PlayCasinoSound(SOUNDKIT.RAID_WARNING); AnnounceGameWin(GC_L("LOC_1586"), winAmt) 
                else 
                    horseFrame.msg:SetText(GC_L("LOC_1587") .. winner .. GC_L("LOC_1588")) 
                end
                C_Timer.After(4, function() 
                    for i=1,4 do horseFrame.horses[i]:SetPoint("CENTER", horseFrame.track, "TOPLEFT", 20, -25 - (i-1)*50) end
                    horseFrame.msg:SetText(GC_L("LOC_1591")) 
                end)
            end
        end)
    end
    for i=1,4 do 
        local b = CreateModernButton(horseFrame, i..GC_L("LOC_1592"), 75, 30)
        b:SetPoint("BOTTOMLEFT", horseFrame, "BOTTOMLEFT", 100 + (i-1)*85, 45)
        b:SetScript("OnClick", function() 
            local amt = tonumber(horseFrame.betInput:GetText()) or 0
            if not horseFrame.isRacing and amt > 0 and playChips >= amt then 
                UpdatePlayChips(-amt); StartHorseRace(i, amt) 
            elseif playChips < amt then
                horseFrame.msg:SetText(GC_L("LOC_1596"))
            elseif amt <= 0 then
                horseFrame.msg:SetText(GC_L("LOC_1597"))
            end 
        end) 
    end
end

local coinFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); coinFrame:SetAllPoints(); coinFrame:Hide()
do
    coinFrame.text = coinFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); coinFrame.text:SetPoint("CENTER", 0, 80); SetCustomFont(coinFrame.text, 30, "OUTLINE"); coinFrame.text:SetText(GC_L("LOC_1603"))
    coinFrame.betInput = CreateFrame("EditBox", nil, coinFrame, "InputBoxTemplate")
    coinFrame.betInput:SetSize(80, 30); coinFrame.betInput:SetPoint("CENTER", 0, 20)
    coinFrame.betInput:SetNumeric(true); coinFrame.betInput:SetAutoFocus(false); coinFrame.betInput:SetText("50")
    SetCustomFont(coinFrame.betInput, 14)
    local cLbl = coinFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    cLbl:SetPoint("BOTTOMLEFT", coinFrame.betInput, "TOPLEFT", 0, 2); SetCustomFont(cLbl, 10); GC_RegisterLocalizedFontString(cLbl, "LOC_1612")
    local function DoFlip(g)
        local amt = tonumber(coinFrame.betInput:GetText()) or 0
        if amt <= 0 then coinFrame.text:SetText(GC_L("LOC_1613")); return end
        if playChips < amt then coinFrame.text:SetText(GC_L("LOC_1614")); return end
        
        UpdatePlayChips(-amt)
        local r = math.random(1,2) == 1 and GC_L("LOC_1615") or GC_L("LOC_1616")
        if r == g then 
            local winAmt = amt * 2
            UpdatePlayChips(winAmt)
            AddChipTransaction(CleanName(UnitName("player")), winAmt, "Coin Flip")
            coinFrame.text:SetText("|cFF00FF00"..r..GC_L("LOC_1620")..winAmt..")|r"); PlayCasinoSound(SOUNDKIT.RAID_WARNING); AnnounceGameWin("Coin Flip", winAmt) 
        else 
            coinFrame.text:SetText("|cFFFF0000"..r.."! BUKTA.|r") 
        end
    end
    
    local bh = CreateLocalizedButton(coinFrame, "LOC_1625", 120, 40); bh:SetPoint("CENTER", -70, -40); bh:SetScript("OnClick", function() DoFlip(GC_L("LOC_1628")) end)
    local bi = CreateLocalizedButton(coinFrame, "LOC_1629", 120, 40); bi:SetPoint("CENTER", 70, -40); bi:SetScript("OnClick", function() DoFlip(GC_L("LOC_1632")) end)
end

local hiloFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); hiloFrame:SetAllPoints(); hiloFrame:Hide()
hiloFrame.title = hiloFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hiloFrame.title:SetPoint("TOP", 0, -80); SetCustomFont(hiloFrame.title, 20, "OUTLINE"); hiloFrame.title:SetText(GC_L("LOC_1638"))
do
    local curVal, currentPot, isHiLoPlaying = 50, 0, false
    local hPotText = hiloFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); hPotText:SetPoint("TOP", hiloFrame.title, "BOTTOM", 0, -15); SetCustomFont(hPotText, 16, "OUTLINE"); hPotText:SetText(GC_L("LOC_1644"))
    local hCard = hiloFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); hCard:SetPoint("CENTER", 0, 20); SetCustomFont(hCard, 60, "OUTLINE"); hCard:SetText(curVal)
    local bup = CreateLocalizedButton(hiloFrame, "LOC_MANUAL_HIGHER", 120, 40); bup:SetPoint("CENTER", -70, -70); bup:Disable()
    local bdn = CreateLocalizedButton(hiloFrame, "LOC_MANUAL_LOWER", 120, 40); bdn:SetPoint("CENTER", 70, -70); bdn:Disable()
    local bCash = CreateLocalizedButton(hiloFrame, "LOC_1653", 160, 40); bCash:SetPoint("CENTER", 0, -125)

    local function EndHiLo(won)
        isHiLoPlaying = false; bup:Disable(); bdn:Disable(); bCash:SetText(GC_L("LOC_1655"))
        if won and currentPot > 0 then UpdatePlayChips(currentPot); AddChipTransaction(CleanName(UnitName("player")), currentPot, "Hi-Lo"); hiloFrame.title:SetText(GC_L("LOC_1658") .. currentPot .. GC_L("LOC_1659")); PlayCasinoSound(SOUNDKIT.RAID_WARNING); AnnounceGameWin(GC_L("LOC_1660"), currentPot) elseif not won then hiloFrame.title:SetText(GC_L("LOC_1661")) end
        currentPot = 0
    end
    local function DoHiLo(g)
        if not isHiLoPlaying then return end; local n = math.random(1, 100)
        if (g == "H" and n > curVal) or (g == "L" and n < curVal) then currentPot = math.floor(currentPot * 1.5); hiloFrame.title:SetText(GC_L("LOC_1664")); hPotText:SetText(GC_L("LOC_1665") .. currentPot .. GC_L("LOC_1666")); bCash:SetText(GC_L("LOC_1667") .. currentPot .. ")") else EndHiLo(false) end
        curVal = n; hCard:SetText(n)
    end
    bup:SetScript("OnClick", function() DoHiLo("H") end); bdn:SetScript("OnClick", function() DoHiLo("L") end)
    bCash:SetScript("OnClick", function()
        if isHiLoPlaying then EndHiLo(true) else
            if playChips < 30 then hiloFrame.title:SetText(GC_L("LOC_1674")); return end
            UpdatePlayChips(-30); isHiLoPlaying = true; currentPot = 30; curVal = math.random(1, 100); hiloFrame.title:SetText(GC_L("LOC_1675")); hPotText:SetText(GC_L("LOC_1676") .. currentPot .. GC_L("LOC_1677")); hCard:SetText(curVal); bup:Enable(); bdn:Enable(); bCash:SetText(GC_L("LOC_1678") .. currentPot .. ")")
        end
    end)
end

local fbFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); fbFrame:SetAllPoints(); fbFrame:Hide()
do
    fbFrame.teams = {
        "Real Madrid", "Barcelona", "Man. City", "Arsenal", "Bayern München", 
        "PSG", "Juventus", "Liverpool", "Inter", "AC Milan", 
        "Dortmund", "Atletico Madrid", "Bayer Leverkusen", "Chelsea", "Man. United",
        "Tottenham", "Napoli", "Benfica", "FC Porto", "Ajax", 
        "RB Leipzig", "Aston Villa"
    }
    fbFrame.t1, fbFrame.t2 = 1, 2
    fbFrame.score1, fbFrame.score2 = 0, 0
    fbFrame.betType = nil 
    fbFrame.betMarket = 1 
    fbFrame.matchTime = 0
    fbFrame.isMatchActive = false
    
    fbFrame.power1, fbFrame.power2 = 50, 50
    fbFrame.odds1, fbFrame.oddsX, fbFrame.odds2 = 2.0, 3.0, 2.0
    fbFrame.chosenOdds = 0
    fbFrame.stats = { shots1=0, shots2=0, y1=0, y2=0, r1=0, r2=0, c1=0, c2=0 }

    fbFrame.title = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    fbFrame.title:SetPoint("TOP", 0, -60) 
    SetCustomFont(fbFrame.title, 20, "OUTLINE")
    fbFrame.team1Form = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    fbFrame.team1Form:SetPoint("TOPRIGHT", fbFrame.title, "BOTTOMLEFT", -15, -5)
    SetCustomFont(fbFrame.team1Form, 12, "OUTLINE")
    fbFrame.team2Form = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    fbFrame.team2Form:SetPoint("TOPLEFT", fbFrame.title, "BOTTOMRIGHT", 15, -5)
    SetCustomFont(fbFrame.team2Form, 12, "OUTLINE")
    fbFrame.pitch = CreateFrame("Frame", nil, fbFrame)
    fbFrame.pitch:SetSize(360, 220)
    fbFrame.pitch:SetPoint("CENTER", 0, 35) 
    fbFrame.bg = fbFrame.pitch:CreateTexture(nil, "BACKGROUND")
    fbFrame.bg:SetAllPoints()
    fbFrame.bg:SetColorTexture(0.15, 0.5, 0.15, 1)
    fbFrame.timeline = CreateFrame("Frame", nil, fbFrame)
    fbFrame.timeline:SetSize(360, 12)
    fbFrame.timeline:SetPoint("BOTTOMLEFT", fbFrame.pitch, "TOPLEFT", 0, 5)
    local tlBg = fbFrame.timeline:CreateTexture(nil, "BACKGROUND")
    tlBg:SetAllPoints()
    tlBg:SetColorTexture(0, 0, 0, 0.6)
    
    local tlMid = fbFrame.timeline:CreateTexture(nil, "BORDER")
    tlMid:SetSize(2, 12); tlMid:SetPoint("CENTER")
    tlMid:SetColorTexture(1, 1, 1, 0.3)
    
    fbFrame.timelineProgress = fbFrame.timeline:CreateTexture(nil, "ARTWORK")
    fbFrame.timelineProgress:SetPoint("LEFT")
    fbFrame.timelineProgress:SetSize(0.1, 12)
    fbFrame.timelineProgress:SetColorTexture(1, 0.8, 0, 0.5)
    
    fbFrame.timelineIcons = {}

    fbFrame.timeText = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    fbFrame.timeText:SetPoint("BOTTOM", fbFrame.timeline, "TOP", 0, 5)
    SetCustomFont(fbFrame.timeText, 14, "OUTLINE")
    fbFrame.timeText:SetText(GC_L("LOC_1733"))

    local function AddTimelineEvent(minute, eType, team)
        local icon = fbFrame.timeline:CreateTexture(nil, "OVERLAY")
        local xOffset = (minute / 90) * 360
        if xOffset > 352 then xOffset = 352 end 
        icon:SetPoint("LEFT", fbFrame.timeline, "LEFT", xOffset, 0)

        if eType == "GOAL" then
            icon:SetSize(10, 10)
            icon:SetTexture("Interface\\Minimap\\PartyRaidBlips")
            icon:SetColorTexture(team == 1 and 1 or 0.2, team == 1 and 0.2 or 0.6, team == 1 and 0.2 or 1, 1)
        elseif eType == "RED" then
            icon:SetSize(6, 10)
            icon:SetColorTexture(1, 0, 0, 1) 
        end
        table.insert(fbFrame.timelineIcons, icon)
    end

    local function ClearTimeline()
        for _, icon in ipairs(fbFrame.timelineIcons) do icon:Hide() end
        fbFrame.timelineIcons = {}
        fbFrame.timelineProgress:SetWidth(0.1) 
    end
    fbFrame.cLine = fbFrame.pitch:CreateTexture(nil, "BORDER")
    fbFrame.cLine:SetSize(2, 220); fbFrame.cLine:SetPoint("CENTER")
    fbFrame.cLine:SetColorTexture(1, 1, 1, 0.5)
    fbFrame.cCircle = fbFrame.pitch:CreateTexture(nil, "BORDER")
    fbFrame.cCircle:SetSize(60, 60); fbFrame.cCircle:SetPoint("CENTER", fbFrame.pitch, "CENTER", 10, -10)
    fbFrame.cCircle:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    fbFrame.cCircle:SetVertexColor(1, 1, 1, 0.5)
    fbFrame.box1 = fbFrame.pitch:CreateTexture(nil, "BORDER"); fbFrame.box1:SetSize(40, 100); fbFrame.box1:SetPoint("LEFT"); fbFrame.box1:SetColorTexture(1, 1, 1, 0.3)
    fbFrame.box2 = fbFrame.pitch:CreateTexture(nil, "BORDER"); fbFrame.box2:SetSize(40, 100); fbFrame.box2:SetPoint("RIGHT"); fbFrame.box2:SetColorTexture(1, 1, 1, 0.3)
    fbFrame.goalText = fbFrame.pitch:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    fbFrame.goalText:SetPoint("CENTER", 0, 30)
    SetCustomFont(fbFrame.goalText, 35, "OUTLINE")
    fbFrame.goalText:Hide()  
    fbFrame.statsText = fbFrame.pitch:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    fbFrame.statsText:SetPoint("CENTER", 0, 0)
    SetCustomFont(fbFrame.statsText, 14, "OUTLINE")
    fbFrame.statsText:SetJustifyH("CENTER")
    fbFrame.statsText:Hide()
    fbFrame.commentText = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    fbFrame.commentText:SetPoint("TOP", fbFrame.pitch, "BOTTOM", 0, -10)
    SetCustomFont(fbFrame.commentText, 14, "OUTLINE")
    fbFrame.commentText:SetTextColor(0.8, 0.8, 0.8)
    fbFrame.entities = {}
    fbFrame.ball = fbFrame.pitch:CreateTexture(nil, "OVERLAY")
	fbFrame.ball:SetSize(10, 10)
    fbFrame.ball:SetTexture("Interface\\AddOns\\GuildCasino\\Images\\ball.tga")
    table.insert(fbFrame.entities, {frame = fbFrame.ball, cx = 0, cy = 0, tx = 0, ty = 0})
    fbFrame.p1, fbFrame.p2 = {}, {}
    for i=1,5 do
        local p = fbFrame.pitch:CreateTexture(nil, "ARTWORK")
        p:SetSize(10, 10); p:SetTexture("Interface\\Minimap\\PartyRaidBlips"); p:SetColorTexture(1, 0.2, 0.2, 1) 
        fbFrame.p1[i] = p
        table.insert(fbFrame.entities, {frame = p, cx = -50, cy = 0, tx = -50, ty = 0})

        local p2 = fbFrame.pitch:CreateTexture(nil, "ARTWORK")
        p2:SetSize(10, 10); p2:SetTexture("Interface\\Minimap\\PartyRaidBlips"); p2:SetColorTexture(0.2, 0.6, 1, 1) 
        fbFrame.p2[i] = p2
        table.insert(fbFrame.entities, {frame = p2, cx = 50, cy = 0, tx = 50, ty = 0})
    end
    fbFrame.btn1 = CreateLocalizedButton(fbFrame, "LOC_1770", 110, 35)
    fbFrame.btn1:SetPoint("BOTTOMLEFT", fbFrame, "BOTTOMLEFT", 40, 50)    
    fbFrame.btnX = CreateLocalizedButton(fbFrame, "LOC_1773", 110, 35)
    fbFrame.btnX:SetPoint("BOTTOM", fbFrame, "BOTTOM", 0, 50)    
    fbFrame.btn2 = CreateLocalizedButton(fbFrame, "LOC_1776", 110, 35)
    fbFrame.btn2:SetPoint("BOTTOMRIGHT", fbFrame, "BOTTOMRIGHT", -40, 50)
    fbFrame.btnMarket = CreateLocalizedButton(fbFrame, "LOC_1779", 200, 25)
    fbFrame.btnMarket:SetPoint("BOTTOM", fbFrame.btnX, "TOP", 0, 10)
    fbFrame.btnMarket.hl:SetColorTexture(1, 0.8, 0, 0.3)
    fbFrame.startBtn = CreateLocalizedButton(fbFrame, "LOC_1782", 150, 30)
    fbFrame.startBtn:SetPoint("BOTTOM", fbFrame.btnMarket, "TOP", 30, 10)
    fbFrame.betInput = CreateFrame("EditBox", nil, fbFrame, "InputBoxTemplate")
    fbFrame.betInput:SetSize(60, 30)
    fbFrame.betInput:SetPoint("RIGHT", fbFrame.startBtn, "LEFT", -20, 0)
    fbFrame.betInput:SetAutoFocus(false)
    fbFrame.betInput:SetNumeric(true)
    fbFrame.betInput:SetText("50")
    SetCustomFont(fbFrame.betInput, 14)
    local fbLbl = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    fbLbl:SetPoint("BOTTOMLEFT", fbFrame.betInput, "TOPLEFT", 0, 2)
    SetCustomFont(fbLbl, 10)
    GC_RegisterLocalizedFontString(fbLbl, "LOC_1794")
    fbFrame.currentBet = 0
    fbFrame.myBetText = fbFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    fbFrame.myBetText:SetPoint("BOTTOM", fbFrame.startBtn, "TOP", 0, 10)
    SetCustomFont(fbFrame.myBetText, 14, "OUTLINE")
    local function UpdateMarketUI()
        fbFrame.betType = nil
        fbFrame.myBetText:SetText(GC_L("LOC_1800"))
        fbFrame.btn1.hl:SetColorTexture(1, 1, 1, 0.1); fbFrame.btnX.hl:SetColorTexture(1, 1, 1, 0.1); fbFrame.btn2.hl:SetColorTexture(1, 1, 1, 0.1)
        
        if fbFrame.betMarket == 1 then
            fbFrame.btnMarket:SetText(GC_L("LOC_1801"))
            fbFrame.btn1:SetWidth(110); fbFrame.btn2:SetWidth(110); fbFrame.btnX:Show()
            fbFrame.btn1:SetText(GC_L("LOC_1802")..fbFrame.odds1.."x)")
            fbFrame.btnX:SetText(GC_L("LOC_1804")..fbFrame.oddsX.."x)")
            fbFrame.btn2:SetText(GC_L("LOC_1806")..fbFrame.odds2.."x)")
        elseif fbFrame.betMarket == 2 then
            fbFrame.btnMarket:SetText(GC_L("LOC_1808"))
            fbFrame.btn1:SetWidth(165); fbFrame.btn2:SetWidth(165); fbFrame.btnX:Hide()
            fbFrame.btn1:SetText(GC_L("LOC_1821") .. " (1.90x)")
            fbFrame.btn2:SetText(GC_L("LOC_1822") .. " (1.90x)")
        elseif fbFrame.betMarket == 3 then
            fbFrame.btnMarket:SetText(GC_L("LOC_1811"))
            fbFrame.btn1:SetWidth(165); fbFrame.btn2:SetWidth(165); fbFrame.btnX:Hide()
            fbFrame.btn1:SetText(GC_L("LOC_1823") .. " (1.85x)")
            fbFrame.btn2:SetText(GC_L("LOC_1824") .. " (1.85x)")
        end
    end
    fbFrame.UpdateMarketUI = UpdateMarketUI
    fbFrame.btnMarket:SetScript("OnClick", function()
        if fbFrame.isMatchActive then return end
        fbFrame.betMarket = fbFrame.betMarket + 1
        if fbFrame.betMarket > 3 then fbFrame.betMarket = 1 end
        UpdateMarketUI()
    end)
    local function SelectBet(b)
        fbFrame.betType = b
        fbFrame.btn1.hl:SetColorTexture(1, 1, 1, 0.1); fbFrame.btnX.hl:SetColorTexture(1, 1, 1, 0.1); fbFrame.btn2.hl:SetColorTexture(1, 1, 1, 0.1)     
        local marketStr = ""
        if fbFrame.betMarket == 1 then
            if b == 1 then fbFrame.btn1.hl:SetColorTexture(1, 0.8, 0, 0.6); fbFrame.chosenOdds = fbFrame.odds1; marketStr = GC_L("LOC_1816") .. fbFrame.teams[fbFrame.t1] .. ")"
            elseif b == 0 then fbFrame.btnX.hl:SetColorTexture(1, 0.8, 0, 0.6); fbFrame.chosenOdds = fbFrame.oddsX; marketStr = GC_L("LOC_1818")
            elseif b == 2 then fbFrame.btn2.hl:SetColorTexture(1, 0.8, 0, 0.6); fbFrame.chosenOdds = fbFrame.odds2; marketStr = GC_L("LOC_1819") .. fbFrame.teams[fbFrame.t2] .. ")" end
        elseif fbFrame.betMarket == 2 then
            fbFrame.chosenOdds = 1.90
            if b == 1 then fbFrame.btn1.hl:SetColorTexture(1, 0.8, 0, 0.6); marketStr = GC_L("LOC_1821")
            elseif b == 2 then fbFrame.btn2.hl:SetColorTexture(1, 0.8, 0, 0.6); marketStr = GC_L("LOC_1822") end
        elseif fbFrame.betMarket == 3 then
            fbFrame.chosenOdds = 1.85
            if b == 1 then fbFrame.btn1.hl:SetColorTexture(1, 0.8, 0, 0.6); marketStr = GC_L("LOC_1823")
            elseif b == 2 then fbFrame.btn2.hl:SetColorTexture(1, 0.8, 0, 0.6); marketStr = GC_L("LOC_1824") end
        end
        if b ~= -1 then
            fbFrame.myBetText:SetText(GC_L("LOC_1825") .. marketStr .. " - " .. fbFrame.chosenOdds .. "x|r")
        end
    end
    fbFrame.RefreshLanguage = function()
        if fbFrame.isMatchActive then return end
        local selectedBet = fbFrame.betType
        UpdateMarketUI()
        if selectedBet then SelectBet(selectedBet) end
    end
    fbFrame.btn1:SetScript("OnClick", function() SelectBet(1) end)
    fbFrame.btnX:SetScript("OnClick", function() SelectBet(0) end)
    fbFrame.btn2:SetScript("OnClick", function() SelectBet(2) end)
    local function UpdateScoreboard()
        fbFrame.title:SetText("|cFFFF4444" .. fbFrame.teams[fbFrame.t1] .. "|r |cFFFFFFFF" .. fbFrame.score1 .. " - " .. fbFrame.score2 .. "|r |cFF44AAFF" .. fbFrame.teams[fbFrame.t2] .. "|r")
    end
    local function GetFormText(power)
        if power >= 90 then return GC_L("LOC_1836")
        elseif power >= 75 then return GC_L("LOC_1837")
        elseif power >= 60 then return GC_L("LOC_1838")
        elseif power >= 40 then return GC_L("LOC_1839")
        else return GC_L("LOC_1840") end
    end
    local function UpdateFormDisplays()
        local r1Text = fbFrame.stats.r1 > 0 and ("\n|cFFFF0000(-" .. fbFrame.stats.r1 .. GC_L("LOC_1842")) or ""
        local r2Text = fbFrame.stats.r2 > 0 and ("\n|cFFFF0000(-" .. fbFrame.stats.r2 .. GC_L("LOC_1845")) or ""
        fbFrame.team1Form:SetText(GC_L("LOC_MANUAL_FORM_PREFIX") .. GetFormText(fbFrame.power1) .. r1Text)
        fbFrame.team2Form:SetText(GC_L("LOC_MANUAL_FORM_PREFIX") .. GetFormText(fbFrame.power2) .. r2Text)
    end
    fbFrame.UpdateFormDisplays = UpdateFormDisplays
    fbFrame.NewMatchSetup = function()
        fbFrame.isMatchActive = false
        fbFrame.startBtn:Enable(); fbFrame.btn1:Enable(); fbFrame.btnX:Enable(); fbFrame.btn2:Enable(); fbFrame.btnMarket:Enable()
        if fbFrame.betInput then fbFrame.betInput:Enable() end

        fbFrame.t1 = math.random(1, #fbFrame.teams); fbFrame.t2 = math.random(1, #fbFrame.teams)
        while fbFrame.t1 == fbFrame.t2 do fbFrame.t2 = math.random(1, #fbFrame.teams) end
        
        fbFrame.power1 = math.random(30, 100)
        fbFrame.power2 = math.random(30, 100)
        fbFrame.stats = { shots1=0, shots2=0, y1=0, y2=0, r1=0, r2=0, c1=0, c2=0 }
        UpdateFormDisplays()
        ClearTimeline()
        local diff = fbFrame.power1 - fbFrame.power2
        fbFrame.odds1 = math.max(1.1, 2.5 - (diff / 40))
        fbFrame.odds2 = math.max(1.1, 2.5 + (diff / 40))
        fbFrame.oddsX = math.max(1.5, 3.2 - (math.abs(diff) / 60))       
        fbFrame.odds1 = math.floor(fbFrame.odds1 * 100) / 100
        fbFrame.odds2 = math.floor(fbFrame.odds2 * 100) / 100
        fbFrame.oddsX = math.floor(fbFrame.oddsX * 100) / 100
        UpdateMarketUI()
        fbFrame.score1, fbFrame.score2, fbFrame.matchTime = 0, 0, 0
        UpdateScoreboard()      
        fbFrame.bg:SetColorTexture(0.15, 0.5, 0.15, 1)
        fbFrame.statsText:Hide()
        fbFrame.goalText:Hide() 
        fbFrame.timeText:SetText(GC_L("LOC_1849"))
        if fbFrame.betInput then fbFrame.betInput:Enable() end
        fbFrame.commentText:SetText(GC_L("LOC_1850"))   
        fbFrame.entities[1].tx, fbFrame.entities[1].ty = 0, 0
        for i=2, 6 do fbFrame.entities[i].tx, fbFrame.entities[i].ty = math.random(-150, -20), math.random(-100, 100) end
        for i=7, 11 do fbFrame.entities[i].tx, fbFrame.entities[i].ty = math.random(20, 150), math.random(-100, 100) end        
        for _, e in ipairs(fbFrame.entities) do
            e.cx, e.cy = e.tx, e.ty
            e.frame:SetPoint("CENTER", e.cx, e.cy)
        end
        SelectBet(-1)
    end
    fbFrame.NewMatchSetup()
    local genericComments = {
        GC_L("LOC_1852"), GC_L("LOC_1853"),
        GC_L("LOC_1854"), GC_L("LOC_1855"),
        GC_L("LOC_1856"), GC_L("LOC_1857"),
        GC_L("LOC_1858"), GC_L("LOC_1859"),
        GC_L("LOC_1860"), GC_L("LOC_1861")
    }

    local goalComments = {
        GC_L("LOC_1862"), GC_L("LOC_1863"),
        GC_L("LOC_1864"), GC_L("LOC_1865"),
        GC_L("LOC_1866"), GC_L("LOC_1867"),
        GC_L("LOC_1868"), GC_L("LOC_1869")
    }

    fbFrame.startBtn:SetScript("OnClick", function()
        if fbFrame.isMatchActive then return end
        if not fbFrame.betType then fbFrame.timeText:SetText(GC_L("LOC_1871")); return end     
        local betAmount = tonumber(fbFrame.betInput:GetText()) or 0
        if betAmount <= 0 then fbFrame.timeText:SetText(GC_L("LOC_1872")); return end
        if playChips < betAmount then fbFrame.timeText:SetText(GC_L("LOC_1873")); return end       
        fbFrame.currentBet = betAmount 
        UpdatePlayChips(-betAmount)       
        fbFrame.isMatchActive = true
        fbFrame.startBtn:Disable(); fbFrame.btn1:Disable(); fbFrame.btnX:Disable(); fbFrame.btn2:Disable(); fbFrame.btnMarket:Disable()
        fbFrame.betInput:Disable() 
        fbFrame.commentText:SetText(GC_L("LOC_1874"))       
        local tickCount = 0
        local isGoalPaused, isEventPaused, isPenaltyPhase, isCornerPhase = false, false, false, false
        local eventPauseTicks, penaltyTicks, cornerTicks = 0, 0, 0
        local penaltyTeam, penaltyResult, cornerTeam = 1, "", 1
        C_Timer.NewTicker(0.02, function(ticker)
            local maxTicks = 90 * 18
            local totalPassed = (fbFrame.matchTime * 18) + tickCount
            local progressWidth = (totalPassed / maxTicks) * 360
            fbFrame.timelineProgress:SetWidth(math.max(0.1, progressWidth))

            for _, e in ipairs(fbFrame.entities) do
                e.cx = e.cx + (e.tx - e.cx) * 0.15 
                e.cy = e.cy + (e.ty - e.cy) * 0.15
                e.frame:SetPoint("CENTER", e.cx, e.cy)
            end

            if isGoalPaused then
                eventPauseTicks = eventPauseTicks - 1
                if eventPauseTicks <= 0 then
                    isGoalPaused = false
                    fbFrame.goalText:Hide()
                    fbFrame.commentText:SetText(GC_L("LOC_1877"))
                    fbFrame.entities[1].tx, fbFrame.entities[1].ty = 0, 0 
                end
                return 
            elseif isEventPaused then
                eventPauseTicks = eventPauseTicks - 1
                if eventPauseTicks <= 0 then
                    isEventPaused = false
                    fbFrame.commentText:SetText(GC_L("LOC_1878"))
                end
                return
            elseif isPenaltyPhase then
                penaltyTicks = penaltyTicks - 1
                if penaltyTicks == 50 then
                    local totalPower = fbFrame.power1 + fbFrame.power2
                    local chance = (penaltyTeam == 1) and (fbFrame.power1 / totalPower) or (fbFrame.power2 / totalPower)
                    chance = chance + 0.3 
                    
                    if math.random() < chance then
                        penaltyResult = "GOAL"
                        fbFrame.entities[1].tx = (penaltyTeam == 1) and 160 or -160
                        fbFrame.commentText:SetText(GC_L("LOC_1880"))
                        PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                    else
                        penaltyResult = "SAVE"
                        fbFrame.entities[1].tx = (penaltyTeam == 1) and 120 or -120
                        fbFrame.entities[1].ty = math.random(-40, 40)
                        local goalieIdx = (penaltyTeam == 1) and 7 or 2
                        fbFrame.entities[goalieIdx].ty = fbFrame.entities[1].ty 
                        fbFrame.commentText:SetText(GC_L("LOC_1882"))
                    end
                elseif penaltyTicks <= 0 then
                    isPenaltyPhase = false
                    if penaltyResult == "GOAL" then
                        AddTimelineEvent(fbFrame.matchTime, "GOAL", penaltyTeam)
                        if penaltyTeam == 1 then fbFrame.score1 = fbFrame.score1 + 1; fbFrame.stats.shots1 = fbFrame.stats.shots1 + 1 
                        else fbFrame.score2 = fbFrame.score2 + 1; fbFrame.stats.shots2 = fbFrame.stats.shots2 + 1 end
                        UpdateScoreboard()
                        isGoalPaused = true; eventPauseTicks = 80
                    else
                        if penaltyTeam == 1 then fbFrame.stats.shots1 = fbFrame.stats.shots1 + 1 else fbFrame.stats.shots2 = fbFrame.stats.shots2 + 1 end
                        isEventPaused = true; eventPauseTicks = 40
                    end
                end
                return 
            elseif isCornerPhase then
                cornerTicks = cornerTicks - 1
                if cornerTicks == 70 then
                    fbFrame.entities[1].tx = (cornerTeam == 1) and 140 or -140
                    fbFrame.entities[1].ty = 0
                    fbFrame.commentText:SetText(GC_L("LOC_1885"))
                elseif cornerTicks <= 0 then
                    isCornerPhase = false
                    local chance = (cornerTeam == 1) and (fbFrame.power1 / 300) or (fbFrame.power2 / 300) 
                    if math.random() < chance then
                        AddTimelineEvent(fbFrame.matchTime, "GOAL", cornerTeam)
                        if cornerTeam == 1 then fbFrame.score1 = fbFrame.score1 + 1; fbFrame.stats.shots1 = fbFrame.stats.shots1 + 1 
                        else fbFrame.score2 = fbFrame.score2 + 1; fbFrame.stats.shots2 = fbFrame.stats.shots2 + 1 end
                        fbFrame.commentText:SetText(GC_L("LOC_1887"))
                        PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                        UpdateScoreboard()
                        isGoalPaused = true; eventPauseTicks = 80
                    else
                        fbFrame.commentText:SetText(GC_L("LOC_1888"))
                        isEventPaused = true; eventPauseTicks = 30
                    end
                end
                return
            end
            tickCount = tickCount + 1
            if tickCount >= 18 then
                tickCount = 0
                fbFrame.matchTime = fbFrame.matchTime + 1
                fbFrame.timeText:SetText(fbFrame.matchTime .. GC_L("LOC_1889"))               
                if fbFrame.matchTime % 12 == 0 then fbFrame.commentText:SetText(genericComments[math.random(#genericComments)]) end               
                local eventRoll = math.random(1, 1000)               
                if eventRoll > 990 then
                    local rcTeam = math.random(1, 2)
                    AddTimelineEvent(fbFrame.matchTime, "RED", rcTeam)
                    if rcTeam == 1 then
                        fbFrame.power1 = math.max(10, fbFrame.power1 - 30); fbFrame.stats.r1 = fbFrame.stats.r1 + 1
                        fbFrame.commentText:SetText(GC_L("LOC_1891"))
                    else
                        fbFrame.power2 = math.max(10, fbFrame.power2 - 30); fbFrame.stats.r2 = fbFrame.stats.r2 + 1
                        fbFrame.commentText:SetText(GC_L("LOC_1892"))
                    end
                    UpdateFormDisplays(); PlayCasinoSound(SOUNDKIT.RAID_WARNING); isEventPaused = true; eventPauseTicks = 80
                    return
                elseif eventRoll > 975 then
                    isPenaltyPhase = true; penaltyTicks = 120; penaltyTeam = math.random(1, 2)
                    fbFrame.commentText:SetText(GC_L("LOC_1893")); PlayCasinoSound(856)                   
                    fbFrame.entities[1].tx, fbFrame.entities[1].ty = ((penaltyTeam == 1) and 100 or -100), 0
                    local shooterIdx = (penaltyTeam == 1) and 2 or 7
                    fbFrame.entities[shooterIdx].tx, fbFrame.entities[shooterIdx].ty = ((penaltyTeam == 1) and 80 or -80), 0
                    local goalieIdx = (penaltyTeam == 1) and 7 or 2
                    fbFrame.entities[goalieIdx].tx, fbFrame.entities[goalieIdx].ty = ((penaltyTeam == 1) and 160 or -160), 0                   
                    for i = 2, 11 do
                        if i ~= shooterIdx and i ~= goalieIdx then
                            fbFrame.entities[i].tx = (penaltyTeam == 1) and 40 or -40
                            fbFrame.entities[i].ty = -50 + ((i%5)*20)
                        end
                    end
                    return
                elseif eventRoll > 910 then
                    isCornerPhase = true; cornerTicks = 130; cornerTeam = math.random(1, 2)
                    if cornerTeam == 1 then fbFrame.stats.c1 = fbFrame.stats.c1 + 1 else fbFrame.stats.c2 = fbFrame.stats.c2 + 1 end
                    fbFrame.commentText:SetText(GC_L("LOC_1894") .. (cornerTeam==1 and GC_L("LOC_1895") or GC_L("LOC_1896")) .. GC_L("LOC_1897"))
                    
                    local sideY = (math.random(1,2)==1) and 100 or -100
                    fbFrame.entities[1].tx, fbFrame.entities[1].ty = ((cornerTeam == 1) and 160 or -160), sideY
                    local kickerIdx = (cornerTeam == 1) and 2 or 7
                    fbFrame.entities[kickerIdx].tx, fbFrame.entities[kickerIdx].ty = ((cornerTeam == 1) and 160 or -160), sideY
                    
                    for i = 2, 11 do
                        if i ~= kickerIdx then
                            fbFrame.entities[i].tx = ((cornerTeam == 1) and 140 or -140) + math.random(-15, 15)
                            fbFrame.entities[i].ty = math.random(-30, 30)
                        end
                    end
                    return
                end
                local bx, by = fbFrame.entities[1].cx, fbFrame.entities[1].cy
                for i=2, 6 do 
                    if math.random() > 0.7 then fbFrame.entities[i].tx, fbFrame.entities[i].ty = bx + math.random(-30,30), by + math.random(-30,30)
                    else fbFrame.entities[i].tx, fbFrame.entities[i].ty = math.random(-160, 40), math.random(-100, 100) end
                end
                for i=7, 11 do 
                    if math.random() > 0.7 then fbFrame.entities[i].tx, fbFrame.entities[i].ty = bx + math.random(-30,30), by + math.random(-30,30)
                    else fbFrame.entities[i].tx, fbFrame.entities[i].ty = math.random(-40, 160), math.random(-100, 100) end
                end               
                local nbx = fbFrame.entities[1].tx + math.random(-80, 80)
                local nby = fbFrame.entities[1].ty + math.random(-80, 80)
                if nbx > 160 then nbx = 160 elseif nbx < -160 then nbx = -160 end
                if nby > 100 then nby = 100 elseif nby < -100 then nby = -100 end
                fbFrame.entities[1].tx, fbFrame.entities[1].ty = nbx, nby

                if math.random(1, 100) > 90 then
                    if math.random(1, fbFrame.power1 + fbFrame.power2) <= fbFrame.power1 then 
                        fbFrame.stats.shots1 = fbFrame.stats.shots1 + 1 
                        fbFrame.commentText:SetText(GC_L("LOC_1898"))
                    else 
                        fbFrame.stats.shots2 = fbFrame.stats.shots2 + 1 
                        fbFrame.commentText:SetText(GC_L("LOC_1899"))
                    end
                end

                if math.random(1, 100) > 97 then
                    local totalPower = fbFrame.power1 + fbFrame.power2
                    local scorerRoll = math.random(1, totalPower)
                    local scorer = (scorerRoll <= fbFrame.power1) and 1 or 2

                    AddTimelineEvent(fbFrame.matchTime, "GOAL", scorer)

                    if scorer == 1 then
                        fbFrame.score1 = fbFrame.score1 + 1; fbFrame.stats.shots1 = fbFrame.stats.shots1 + 1
                        fbFrame.entities[1].cx, fbFrame.entities[1].cy = 160, 0; fbFrame.entities[1].tx, fbFrame.entities[1].ty = 160, 0 
                        for i=2, 6 do fbFrame.entities[i].tx, fbFrame.entities[i].ty = 140 + math.random(-15, 15), math.random(-25, 25) end 
                        fbFrame.goalText:SetText("|cFFFF4444" .. fbFrame.teams[fbFrame.t1] .. GC_L("LOC_1902"))
                    else
                        fbFrame.score2 = fbFrame.score2 + 1; fbFrame.stats.shots2 = fbFrame.stats.shots2 + 1
                        fbFrame.entities[1].cx, fbFrame.entities[1].cy = -160, 0; fbFrame.entities[1].tx, fbFrame.entities[1].ty = -160, 0 
                        for i=7, 11 do fbFrame.entities[i].tx, fbFrame.entities[i].ty = -140 + math.random(-15, 15), math.random(-25, 25) end
                        fbFrame.goalText:SetText("|cFF44AAFF" .. fbFrame.teams[fbFrame.t2] .. GC_L("LOC_1904"))
                    end
                    UpdateScoreboard(); fbFrame.goalText:Show()
                    fbFrame.commentText:SetText("|cFFFFFF00" .. goalComments[math.random(#goalComments)] .. "|r")
                    PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                    isGoalPaused = true; eventPauseTicks = 80 
                end
            end

            if fbFrame.matchTime >= 90 then
                ticker:Cancel()
				fbFrame.isMatchActive = false              
                fbFrame.commentText:SetText(GC_L("LOC_1907"))                
                local totalPow = fbFrame.power1 + fbFrame.power2
                local p1Poss = math.floor((fbFrame.power1 / totalPow) * 100) + math.random(-6, 6)
                p1Poss = math.max(20, math.min(80, p1Poss))
                local p2Poss = 100 - p1Poss
                fbFrame.stats.y1 = fbFrame.stats.y1 + math.random(0, 4); fbFrame.stats.y2 = fbFrame.stats.y2 + math.random(0, 4)
                local totalGoals = fbFrame.score1 + fbFrame.score2
                local totalCorners = fbFrame.stats.c1 + fbFrame.stats.c2
                
                local statsString = GC_L("LOC_1908")
                statsString = statsString .. GC_L("LOC_1909") .. p1Poss .. "% - " .. p2Poss .. "%|r\n"
                statsString = statsString .. GC_L("LOC_1912") .. fbFrame.stats.shots1 .. " - " .. fbFrame.stats.shots2 .. "|r\n"
                statsString = statsString .. GC_L("LOC_1915") .. fbFrame.stats.c1 .. " - " .. fbFrame.stats.c2 .. GC_L("LOC_1917") .. totalCorners .. ")|r\n"
                statsString = statsString .. GC_L("LOC_1919") .. fbFrame.stats.y1 .. " - " .. fbFrame.stats.y2 .. "|r\n"
                statsString = statsString .. GC_L("LOC_1922") .. fbFrame.stats.r1 .. " - " .. fbFrame.stats.r2 .. "|r"

                fbFrame.bg:SetColorTexture(0.05, 0.2, 0.05, 0.9)
                fbFrame.goalText:Hide() 
                fbFrame.statsText:SetText(statsString); fbFrame.statsText:Show()
                local isWin = false
                if fbFrame.betMarket == 1 then
                    local winner = 0 
                    if fbFrame.score1 > fbFrame.score2 then winner = 1 elseif fbFrame.score2 > fbFrame.score1 then winner = 2 end
                    isWin = (fbFrame.betType == winner)
                elseif fbFrame.betMarket == 2 then
                    if fbFrame.betType == 1 and totalGoals < 2.5 then isWin = true
                    elseif fbFrame.betType == 2 and totalGoals > 2.5 then isWin = true end
                elseif fbFrame.betMarket == 3 then
                    if fbFrame.betType == 1 and totalCorners < 5.5 then isWin = true
                    elseif fbFrame.betType == 2 and totalCorners > 5.5 then isWin = true end
                end
                
                if isWin then
                    local winAmt = math.floor(fbFrame.currentBet * fbFrame.chosenOdds) 
                    UpdatePlayChips(winAmt)
					AddChipTransaction(CleanName(UnitName("player")), winAmt, "Match Bet")
                    fbFrame.timeText:SetText(GC_L("LOC_1927") .. winAmt .. GC_L("LOC_1928") .. fbFrame.chosenOdds .. "x odds)")
                    PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                    AnnounceGameWin("Match Bet (" .. fbFrame.chosenOdds .. "x)", winAmt)
                else
                    fbFrame.timeText:SetText(GC_L("LOC_1932") .. fbFrame.currentBet .. GC_L("LOC_1933"))
                end
                
                C_Timer.After(10, function()
                    if not fbFrame.isMatchActive then fbFrame.NewMatchSetup() end
                end)
            end
        end) 
    end)
end

local fishFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); fishFrame:SetAllPoints(); fishFrame:Hide()
do
    fishFrame.title = fishFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    fishFrame.title:SetPoint("TOP", 0, -70)
    SetCustomFont(fishFrame.title, 20, "OUTLINE")
    GC_RegisterLocalizedFontString(fishFrame.title, "LOC_GAME_ANGLERS_LIFE")
    local baits = {
        {localeKey = "LOC_1940", cost = 50, col = "|cFFFFFFFF"},
        {localeKey = "LOC_1942", cost = 100, col = "|cFF1EFF00"},
        {localeKey = "LOC_1944", cost = 200, col = "|cffa335ee"}
    }
    local currentBait = 1
    local fState = "IDLE"

    local fishLootTable = {
        {localeKey="LOC_1947", col="|cFF9D9D9D", icon="Interface\\Icons\\INV_Boots_01", mult=0,   w={400, 300, 0},   diff={speed=0.5, erratic=0.1}},
        {localeKey="LOC_1950",  col="|cFF9D9D9D", icon="Interface\\Icons\\inv_misc_fish_96", mult=0.2, w={250, 350, 600}, diff={speed=0.6, erratic=0.2}},
        {localeKey="LOC_1953",     col="|cFFFFFFFF", icon="Interface\\Icons\\inv_fishing_redtailloach", mult=0.8, w={200, 220, 280}, diff={speed=1.5, erratic=0.4}},
        {localeKey="LOC_1956",   col="|cFF1EFF00", icon="Interface\\Icons\\inv_fishing_greatseacatfish", mult=2,   w={100, 90,  80},  diff={speed=2.5, erratic=0.6}},
        {localeKey="LOC_1959",   col="|cFF0070DD", icon="Interface\\Icons\\inv_magicalfishpet", mult=5,   w={40,  30,  30},  diff={speed=4.0, erratic=0.8}},
        {localeKey="LOC_1962",  col="|cffa335ee", icon="Interface\\Icons\\inv_fish_blackbarracudablue", mult=15, w={9,   8,   8},   diff={speed=6.0, erratic=0.9}},
        {localeKey="LOC_1965",    col="|cFFFF00FF", icon="Interface\\Icons\\inv_sword_2h_artifactashbringer_d_01", mult=50,  w={1,   2,   2},   diff={speed=8.5, erratic=1.0}}
    }

    fishFrame.infoBox = CreateFrame("Frame", nil, fishFrame, "BackdropTemplate")
    fishFrame.infoBox:SetSize(160, 200)
    fishFrame.infoBox:SetPoint("LEFT", 10, -10)    
    local infoTitle = fishFrame.infoBox:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    infoTitle:SetPoint("TOPLEFT", 0, 0); GC_RegisterLocalizedFontString(infoTitle, "LOC_1974")
    fishFrame.infoLines = {}
    for i = 1, #fishLootTable do
        local fs = fishFrame.infoBox:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        fs:SetPoint("TOPLEFT", 0, -15 - (i*25)) 
        SetCustomFont(fs, 12, "OUTLINE") 
        fishFrame.infoLines[i] = fs
    end
    local function UpdateInfoBox()
        local cCost = baits[currentBait].cost
        for i, fish in ipairs(fishLootTable) do
            local winAmt = math.floor(cCost * fish.mult)
            local chanceText = (fish.w[currentBait] > 0) and ("|cFF00FF00" .. winAmt .. GC_L("LOC_1980")) or GC_L("LOC_1981")
            fishFrame.infoLines[i]:SetText(fish.col .. GC_L(fish.localeKey) .. "|r\n  -> " .. chanceText)
            fishFrame.infoLines[i]:SetAlpha(fish.w[currentBait] > 0 and 1 or 0.4)
        end
    end
    fishFrame.statusText = fishFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    fishFrame.statusText:SetPoint("TOP", fishFrame.title, "BOTTOM", 0, -10)
    SetCustomFont(fishFrame.statusText, 14, "OUTLINE")
    fishFrame.statusText:SetText(GC_L("LOC_1988"))

    fishFrame.water = CreateFrame("Frame", nil, fishFrame)
    fishFrame.water:SetSize(280, 160)
    fishFrame.water:SetPoint("CENTER", 60, 0) 
    local wbg = fishFrame.water:CreateTexture(nil, "BACKGROUND")
    wbg:SetAllPoints(); wbg:SetColorTexture(0.05, 0.3, 0.5, 0.7)   
    fishFrame.bobber = fishFrame.water:CreateTexture(nil, "OVERLAY")
    fishFrame.bobber:SetSize(30, 30)
    fishFrame.bobber:SetTexture("Interface\\Icons\\Trade_Fishing")
    fishFrame.bobber:SetPoint("CENTER", 0, 0)
    fishFrame.bobber:Hide()
    fishFrame.lootIcon = fishFrame.water:CreateTexture(nil, "OVERLAY")
    fishFrame.lootIcon:SetSize(60, 60); fishFrame.lootIcon:SetPoint("CENTER", 0, 10); fishFrame.lootIcon:Hide()
    fishFrame.lootText = fishFrame.water:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    fishFrame.lootText:SetPoint("TOP", fishFrame.lootIcon, "BOTTOM", 0, -5); SetCustomFont(fishFrame.lootText, 16, "OUTLINE"); fishFrame.lootText:Hide()
    fishFrame.mgFrame = CreateFrame("Frame", nil, fishFrame.water)
    fishFrame.mgFrame:SetSize(40, 140)
    fishFrame.mgFrame:SetPoint("RIGHT", fishFrame.water, "RIGHT", -20, 0)
    fishFrame.mgFrame:Hide()

    local mgBg = fishFrame.mgFrame:CreateTexture(nil, "BACKGROUND")
    mgBg:SetAllPoints(); mgBg:SetColorTexture(0, 0, 0, 0.6)
    fishFrame.mgZone = fishFrame.mgFrame:CreateTexture(nil, "ARTWORK")
    fishFrame.mgZone:SetSize(36, 40)
    fishFrame.mgZone:SetPoint("BOTTOM", 0, 2)
    fishFrame.mgZone:SetColorTexture(0.2, 0.8, 0.2, 0.5)
    fishFrame.mgFish = fishFrame.mgFrame:CreateTexture(nil, "OVERLAY")
    fishFrame.mgFish:SetSize(20, 20)
    fishFrame.mgFish:SetTexture("Interface\\Icons\\INV_Misc_Fish_04")
    fishFrame.mgFish:SetPoint("BOTTOM", 0, 2)
    fishFrame.progBarBg = CreateFrame("Frame", nil, fishFrame.mgFrame)
    fishFrame.progBarBg:SetSize(10, 140)
    fishFrame.progBarBg:SetPoint("RIGHT", fishFrame.mgFrame, "LEFT", -5, 0)
    local pbbgtex = fishFrame.progBarBg:CreateTexture(nil, "BACKGROUND")
    pbbgtex:SetAllPoints(); pbbgtex:SetColorTexture(0,0,0,0.8)
    fishFrame.progBar = fishFrame.progBarBg:CreateTexture(nil, "ARTWORK")
    fishFrame.progBar:SetSize(8, 1)
    fishFrame.progBar:SetPoint("BOTTOM", 0, 1)
    fishFrame.progBar:SetColorTexture(1, 0.8, 0, 1)
    fishFrame.catchButton = CreateFrame("Button", nil, fishFrame)
    fishFrame.catchButton:SetAllPoints(fishFrame)
    fishFrame.catchButton:Hide()

    fishFrame.baitBtns = {}
    for i, b in ipairs(baits) do
        local btn = CreateModernButton(fishFrame, GC_L(b.localeKey) .. "\n(" .. b.cost .. ")", 90, 35)
        btn:SetPoint("BOTTOMLEFT", fishFrame.water, "BOTTOMLEFT", (i-1)*100, -50)
        btn:SetScript("OnClick", function()
            if fState ~= "IDLE" and fState ~= "LOOT" then return end 
            
            currentBait = i
            for _, otherBtn in ipairs(fishFrame.baitBtns) do
                otherBtn.hl:SetColorTexture(1, 1, 1, 0.1)
                otherBtn:GetFontString():SetTextColor(0.6, 0.6, 0.6)
            end
            btn.hl:SetColorTexture(1, 0.8, 0, 0.4)
            btn:GetFontString():SetTextColor(1, 1, 1)
            UpdateInfoBox()
            fishFrame.actionBtn:SetText(GC_L("LOC_2025") .. baits[currentBait].cost .. ")")
        end)
        fishFrame.baitBtns[i] = btn
    end

    fishFrame.actionBtn = CreateLocalizedButton(fishFrame, "LOC_2027", 180, 40)
    fishFrame.actionBtn:SetPoint("BOTTOM", fishFrame.water, "BOTTOM", 0, -100)
    fishFrame.actionBtn.bg:SetColorTexture(0.1, 0.5, 0.1, 0.9)

    fishFrame.RefreshLanguage = function()
        for i, b in ipairs(baits) do
            if fishFrame.baitBtns[i] then
                fishFrame.baitBtns[i]:SetText(GC_L(b.localeKey) .. "\n(" .. b.cost .. ")")
            end
        end
        UpdateInfoBox()
        if fState == "IDLE" then
            fishFrame.statusText:SetText(GC_L("LOC_1988"))
            fishFrame.actionBtn:SetText(GC_L("LOC_2025") .. baits[currentBait].cost .. ")")
        elseif fState == "LOOT" then
            fishFrame.actionBtn:SetText(GC_L("LOC_2047"))
        elseif fState == "MINIGAME" then
            fishFrame.actionBtn:SetText(GC_L("LOC_MANUAL_HOLD_MOUSE"))
        end
    end

    fishFrame.baitBtns[1]:Click()

    local fishTicker = nil
    local activeFish = nil

    local isReeling = false
    local zonePos = 0 
    local zoneVelocity = 0
    local fishPos = 0
    local fishTarget = 0
    local fishTimer = 0
    local catchProgress = 30

    fishFrame.catchButton:SetScript("OnMouseDown", function() isReeling = true end)
    fishFrame.catchButton:SetScript("OnMouseUp", function() isReeling = false end)
    fishFrame.catchButton:SetScript("OnHide", function() isReeling = false end)

    local function EndMiniGame(won)
        fState = "LOOT"
        fishFrame.mgFrame:Hide()
        fishFrame.catchButton:Hide()
        fishFrame.mgFrame:SetScript("OnUpdate", nil)
        isReeling = false

        if won then
            local winAmt = math.floor(baits[currentBait].cost * activeFish.mult)
            fishFrame.lootIcon:SetTexture(activeFish.icon); fishFrame.lootIcon:Show()
            fishFrame.lootText:SetText(activeFish.col .. GC_L(activeFish.localeKey) .. "|r\n" .. (winAmt > 0 and ("|cFF00FF00+"..winAmt..GC_L("LOC_2037")) or GC_L("LOC_2038")))
            fishFrame.lootText:Show()
            
            if winAmt > 0 then
                UpdatePlayChips(winAmt)
				AddChipTransaction(CleanName(UnitName("player")), winAmt, GC_L("LOC_2040"))
                fishFrame.statusText:SetText(GC_L("LOC_2041"))
                if activeFish.mult >= 5 then 
                    PlayCasinoSound(856)
                    AnnounceGameWin(GC_L("LOC_2042"), winAmt .. " (" .. GC_L(activeFish.localeKey) .. ")") 
                else
                    PlaySound(856)
                end
            else
                fishFrame.statusText:SetText(GC_L("LOC_2045"))
            end
        else
            fishFrame.statusText:SetText(GC_L("LOC_2046"))
            PlaySound(856)
        end

        fishFrame.actionBtn:SetText(GC_L("LOC_2047"))
        fishFrame.actionBtn.bg:SetColorTexture(0.1, 0.5, 0.1, 0.9)
        for _, b in ipairs(fishFrame.baitBtns) do b:Enable() end
        fishFrame.actionBtn:Enable()
    end

    local function StartMiniGame()
        fState = "MINIGAME"
        fishFrame.actionBtn:Disable()
        fishFrame.actionBtn:SetText(GC_L("LOC_MANUAL_HOLD_MOUSE"))
        fishFrame.actionBtn.bg:SetColorTexture(0.8, 0.1, 0.1, 0.9)
        
        local totalW = 0
        for _, f in ipairs(fishLootTable) do totalW = totalW + f.w[currentBait] end
        local roll = math.random(1, totalW)
        local curW = 0
        activeFish = fishLootTable[1]
        for _, f in ipairs(fishLootTable) do
            curW = curW + f.w[currentBait]
            if roll <= curW then activeFish = f; break end
        end

        zonePos = 0; zoneVelocity = 0; fishPos = 20; fishTarget = 20; fishTimer = 0; catchProgress = 30
        fishFrame.mgFrame:Show()
        fishFrame.catchButton:Show()
        fishFrame.progBar:SetHeight(math.max(1, (catchProgress / 100) * 138))

        local lastTime = GetTime()
        fishFrame.mgFrame:SetScript("OnUpdate", function(self)
            local now = GetTime()
            local dt = now - lastTime
            if dt > 0.1 then dt = 0.1 end 
            lastTime = now

            if isReeling then
                zoneVelocity = zoneVelocity + (1000 * dt) 
            else
                zoneVelocity = zoneVelocity - (1000 * dt) 
            end
            
            zoneVelocity = zoneVelocity * 0.85
            zonePos = zonePos + (zoneVelocity * dt)

            if zonePos > 100 then 
                zonePos = 100; zoneVelocity = 0 
            end
            if zonePos < 0 then 
                zonePos = 0
                if zoneVelocity < -30 then zoneVelocity = -zoneVelocity * 0.35 else zoneVelocity = 0 end
            end
            
            fishFrame.mgZone:SetPoint("BOTTOM", 0, (zonePos / 100) * 96 + 2)

            fishTimer = fishTimer - dt
            if fishTimer <= 0 then
                fishTimer = math.random() * (1.5 / activeFish.diff.speed) + 0.2
                fishTarget = fishPos + ((math.random() * 100 - 50) * activeFish.diff.erratic * 2)
                if fishTarget > 100 then fishTarget = 100 elseif fishTarget < 0 then fishTarget = 0 end
            end
            
            fishPos = fishPos + ((fishTarget - fishPos) * activeFish.diff.speed * dt)
            fishFrame.mgFish:SetPoint("BOTTOM", 0, (fishPos / 100) * 116 + 2)

            local zoneCenterY = zonePos + 20 
            local fishCenterY = fishPos + 10
            
            if math.abs(zoneCenterY - fishCenterY) < 20 then
                fishFrame.mgZone:SetColorTexture(0.2, 0.8, 0.2, 0.8)
                catchProgress = catchProgress + (15 * dt)
            else
                fishFrame.mgZone:SetColorTexture(0.8, 0.2, 0.2, 0.8)
                catchProgress = catchProgress - (10 * dt)
            end

            if catchProgress > 100 then catchProgress = 100 end
            fishFrame.progBar:SetHeight(math.max(1, (catchProgress / 100) * 138))
            
            if catchProgress > 75 then fishFrame.progBar:SetColorTexture(0.2, 1, 0.2, 1)
            elseif catchProgress > 30 then fishFrame.progBar:SetColorTexture(1, 0.8, 0, 1)
            else fishFrame.progBar:SetColorTexture(1, 0, 0, 1) end

            if catchProgress >= 100 then EndMiniGame(true)
            elseif catchProgress <= 0 then EndMiniGame(false) end
        end)
    end

    fishFrame.actionBtn:SetScript("OnClick", function()
        if fState == "IDLE" or fState == "LOOT" then
            local cost = baits[currentBait].cost
            if playChips < cost then fishFrame.statusText:SetText(GC_L("LOC_2056")); return end
            UpdatePlayChips(-cost)
            
            fState = "WAITING"
            for _, b in ipairs(fishFrame.baitBtns) do b:Disable() end
            fishFrame.lootIcon:Hide(); fishFrame.lootText:Hide()
            
            fishFrame.bobber:ClearAllPoints()
            fishFrame.bobber:SetPoint("CENTER", fishFrame.water, "CENTER", -40, 0)
            fishFrame.bobber:Show()
            
            fishFrame.statusText:SetText(GC_L("LOC_2060"))
            fishFrame.actionBtn:Disable()
            fishFrame.actionBtn:SetText(GC_L("LOC_2061"))
            fishFrame.actionBtn.bg:SetColorTexture(0.5, 0.5, 0.5, 0.9)
            PlaySound(856)
            
            local tick = 0
            local timeToBite = math.random(20, 50) 
            
            fishTicker = C_Timer.NewTicker(0.1, function()
                tick = tick + 1
                local bobberY = math.sin(tick * 0.5) * 5
                fishFrame.bobber:ClearAllPoints()
                fishFrame.bobber:SetPoint("CENTER", fishFrame.water, "CENTER", -40, bobberY)
                
                if tick == timeToBite - 10 then
                    fishFrame.statusText:SetText(GC_L("LOC_2064"))
                elseif tick == timeToBite then
                    fishTicker:Cancel()
                    fishFrame.statusText:SetText(GC_L("LOC_2065"))
                    fishFrame.bobber:Hide()
                    PlaySound(856)
                    StartMiniGame()
                end
            end, timeToBite + 1)
        end
    end)
end

local caseFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); caseFrame:SetAllPoints(); caseFrame:Hide()
do
    caseFrame.title = caseFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    caseFrame.title:SetPoint("TOP", 0, -70)
    SetCustomFont(caseFrame.title, 20, "OUTLINE")
    caseFrame.title:SetText(GC_L("LOC_2071"))

    caseFrame.sliderWindow = CreateFrame("Frame", nil, caseFrame, "BackdropTemplate")
    caseFrame.sliderWindow:SetSize(400, 80)
    caseFrame.sliderWindow:SetPoint("TOP", 0, -190) 
    caseFrame.sliderWindow:SetClipsChildren(true)    
    local cbg = caseFrame.sliderWindow:CreateTexture(nil, "BACKGROUND")
    cbg:SetAllPoints()
    cbg:SetColorTexture(0.05, 0.05, 0.05, 0.9)    
    local border = caseFrame.sliderWindow:CreateTexture(nil, "BORDER")
    border:SetAllPoints()
    border:SetColorTexture(1, 1, 1, 0.1)
    caseFrame.container = CreateFrame("Frame", nil, caseFrame.sliderWindow)
    caseFrame.container:SetSize(10, 80)
    caseFrame.container:SetPoint("LEFT", 0, 0)
    caseFrame.lineIndicator = CreateFrame("Frame", nil, caseFrame.sliderWindow)
    caseFrame.lineIndicator:SetAllPoints()
    caseFrame.lineIndicator:SetFrameLevel(caseFrame.container:GetFrameLevel() + 10) 

    caseFrame.centerLine = caseFrame.lineIndicator:CreateTexture(nil, "OVERLAY")
    caseFrame.centerLine:SetSize(4, 80)
    caseFrame.centerLine:SetPoint("CENTER")
    caseFrame.centerLine:SetColorTexture(1, 0.8, 0, 0.95)
    caseFrame.icons = {}
    for i = 1, 70 do
        local f = CreateFrame("Frame", nil, caseFrame.container, "BackdropTemplate")
        f:SetSize(60, 60)
        f:SetPoint("LEFT", (i-1)*64 + 10, 0) 
        
        f.bg = f:CreateTexture(nil, "BACKGROUND")
        f.bg:SetPoint("TOPLEFT", -2, 2)
        f.bg:SetPoint("BOTTOMRIGHT", 2, -2)
        
        f.tex = f:CreateTexture(nil, "ARTWORK")
        f.tex:SetAllPoints()
        f.tex:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        caseFrame.icons[i] = f
    end
    caseFrame.resultText = caseFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    caseFrame.resultText:SetPoint("TOP", caseFrame.sliderWindow, "BOTTOM", 0, -15)
    SetCustomFont(caseFrame.resultText, 18, "OUTLINE")
    caseFrame.resultText:SetText(GC_L("LOC_2094"))
    caseFrame.actionBtn = CreateLocalizedButton(caseFrame, "LOC_2095", 180, 40)
    caseFrame.actionBtn:SetPoint("TOP", caseFrame.resultText, "BOTTOM", 0, -15)
    caseFrame.actionBtn.bg:SetColorTexture(0.2, 0.6, 0.2, 0.9)
    local caseLootTable = {
        {name="Kopott Vas Kard", rarity=GC_L("LOC_2099"), color={0.2, 0.4, 1}, mult=0.1, icon="Interface\\Icons\\INV_Sword_04", chance=1300},
        {name=GC_L("LOC_2101"), rarity=GC_L("LOC_2102"), color={0.2, 0.4, 1}, mult=0.2, icon="Interface\\Icons\\INV_Chest_Leather_08", chance=1300},
        {name=GC_L("LOC_2104"), rarity=GC_L("LOC_2105"), color={0.2, 0.4, 1}, mult=0.3, icon="Interface\\Icons\\INV_Shield_05", chance=1300},
        {name=GC_L("LOC_2107"), rarity=GC_L("LOC_2108"), color={0.2, 0.4, 1}, mult=0.4, icon="Interface\\Icons\\INV_Misc_Spyglass_02", chance=1300},
        {name=GC_L("LOC_2110"), rarity=GC_L("LOC_2111"), color={0.2, 0.4, 1}, mult=0.5, icon="Interface\\Icons\\INV_Weapon_Rifle_01", chance=1100},
        {name=GC_L("LOC_2113"), rarity=GC_L("LOC_2114"), color={0.2, 0.4, 1}, mult=0.6, icon="Interface\\Icons\\INV_Boots_01", chance=1100},
        {name=GC_L("LOC_2116"), rarity=GC_L("LOC_2117"), color={0.6, 0.2, 0.8}, mult=1.0, icon="Interface\\Icons\\INV_Weapon_ShortBlade_05", chance=800},
        {name=GC_L("LOC_2119"), rarity=GC_L("LOC_2120"), color={0.6, 0.2, 0.8}, mult=1.2, icon="Interface\\Icons\\INV_Jewelry_Amulet_04", chance=600},
        {name=GC_L("LOC_2122"), rarity=GC_L("LOC_2123"), color={0.6, 0.2, 0.8}, mult=1.5, icon="Interface\\Icons\\INV_Jewelry_Ring_03", chance=515},
        {name=GC_L("LOC_2125"), rarity=GC_L("LOC_2126"), color={1, 0.2, 0.6}, mult=3.0, icon="Interface\\Icons\\INV_Gauntlets_17", chance=428},
        {name=GC_L("LOC_2128"), rarity=GC_L("LOC_2129"), color={1, 0.2, 0.6}, mult=4.0, icon="Interface\\Icons\\INV_Misc_Bone_Skull_02", chance=120},
        {name=GC_L("LOC_2131"), rarity=GC_L("LOC_2132"), color={1, 0.2, 0.6}, mult=5.0, icon="Interface\\Icons\\INV_Weapon_Bow_08", chance=80},
        {name=GC_L("LOC_2134"), rarity=GC_L("LOC_2135"), color={0.9, 0.1, 0.1}, mult=15.0, icon="Interface\\Icons\\INV_Helmet_74", chance=30},
        {name=GC_L("LOC_2137"), rarity=GC_L("LOC_2138"), color={0.9, 0.1, 0.1}, mult=25.0, icon="Interface\\Icons\\INV_Weapon_Glave_01", chance=20},
        {name=GC_L("LOC_2140"), rarity=GC_L("LOC_2141"), color={1, 0.8, 0}, mult=50.0, icon="Interface\\Icons\\INV_Gauntlets_14", chance=5},
        {name="Karambit | Fade", rarity=GC_L("LOC_2144"), color={1, 0.8, 0}, mult=100.0, icon="Interface\\Icons\\INV_Weapon_ShortBlade_14", chance=2}
    }

    caseFrame.previewTitle = caseFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    caseFrame.previewTitle:SetPoint("BOTTOM", 0, 200)
    SetCustomFont(caseFrame.previewTitle, 14, "OUTLINE")
    caseFrame.previewTitle:SetText(GC_L("LOC_2150"))

    caseFrame.previewItems = {}
    local cols = 8
    local pIconSize = 35
    local spacing = 6
    local startX = -((cols * pIconSize + (cols - 1) * spacing) / 2) + (pIconSize / 2)
    local startY = 150

    for i, loot in ipairs(caseLootTable) do
        local row = math.floor((i - 1) / cols)
        local col = (i - 1) % cols    
        local btn = CreateFrame("Button", nil, caseFrame)
        btn:SetSize(pIconSize, pIconSize)
        btn:SetPoint("BOTTOM", startX + col * (pIconSize + spacing), startY - row * (pIconSize + spacing))       
        btn.bg = btn:CreateTexture(nil, "BACKGROUND")
        btn.bg:SetPoint("TOPLEFT", -2, 2); btn.bg:SetPoint("BOTTOMRIGHT", 2, -2)
        btn.bg:SetColorTexture(unpack(loot.color))      
        btn.tex = btn:CreateTexture(nil, "ARTWORK")
        btn.tex:SetAllPoints(); btn.tex:SetTexture(loot.icon)
        btn.tex:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        btn:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:AddLine(loot.name, unpack(loot.color))
            GameTooltip:AddLine(GC_L("LOC_2159") .. loot.rarity, 1, 1, 1)
            GameTooltip:AddLine(GC_L("LOC_2160") .. math.floor(150 * loot.mult) .. GC_L("LOC_2161"), 0, 1, 0)
            GameTooltip:AddLine(GC_L("LOC_2162") .. (loot.chance / 100) .. "%", 0.8, 0.8, 0.8)
            GameTooltip:Show()
        end)
        btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
    end

    local isOpening = false

    local function EndCaseOpening(outcome)
        isOpening = false
        caseFrame.actionBtn:Enable()
        local winAmt = math.floor(150 * outcome.mult)
        
        if winAmt > 0 then
            UpdatePlayChips(winAmt)
			AddChipTransaction(CleanName(UnitName("player")), winAmt, GC_L("LOC_2166"))
            caseFrame.resultText:SetText(GC_L("LOC_2167") .. outcome.name .. "\n|cFF00FF00(+" .. winAmt .. GC_L("LOC_2169"))
            if outcome.mult >= 15 then 
                PlayCasinoSound(8440) 
                AnnounceGameWin(GC_L("LOC_2170")..outcome.name..")", winAmt)
            elseif outcome.mult >= 3 then 
                PlayCasinoSound(SOUNDKIT.RAID_WARNING)
            else 
                PlaySound(856) 
            end
        else
            caseFrame.resultText:SetText(GC_L("LOC_2172") .. outcome.name .. GC_L("LOC_2173"))
            PlaySound(856)
        end
    end

    caseFrame.actionBtn:SetScript("OnClick", function()
        if isOpening then return end
        if playChips < 150 then caseFrame.resultText:SetText(GC_L("LOC_2175")); return end
        
        UpdatePlayChips(-150)
        isOpening = true
        caseFrame.actionBtn:Disable()
        caseFrame.resultText:SetText(GC_L("LOC_2176"))
        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        local roll = math.random(1, 10000)
        local outcome
        local acc = 0
        for _, loot in ipairs(caseLootTable) do
            acc = acc + loot.chance
            if roll <= acc then outcome = loot; break end
        end

        for i = 1, 70 do
            local rLoot
            if i == 63 then 
                rLoot = outcome 
            else
                local r = math.random(1, 10000)
                local a = 0
                for _, loot in ipairs(caseLootTable) do
                    a = a + loot.chance
                    if r <= a then rLoot = loot; break end
                end
            end
            caseFrame.icons[i].tex:SetTexture(rLoot.icon)
            caseFrame.icons[i].bg:SetColorTexture(unpack(rLoot.color))
        end
        caseFrame.container:SetPoint("LEFT", 0, 0)
        local currentX = 0

        local targetX = -3808 + math.random(-10, 10)
        local lastIndex = 0

        caseFrame.container:SetScript("OnUpdate", function(self, elapsed)
            currentX = currentX + (targetX - currentX) * (elapsed * 1.5) 
            self:SetPoint("LEFT", currentX, 0)
            
            local currentIndex = math.floor((192 - currentX) / 64)
            if currentIndex ~= lastIndex then
                PlaySound(856) 
                lastIndex = currentIndex
            end

            if math.abs(targetX - currentX) < 0.5 then
                self:SetScript("OnUpdate", nil)
                EndCaseOpening(outcome)
            end
        end)
    end)
end

local megaFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); megaFrame:SetAllPoints(); megaFrame:Hide()
do
    megaFrame.title = megaFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    megaFrame.title:SetPoint("TOP", 0, -60)
    SetCustomFont(megaFrame.title, 20, "OUTLINE")
    GC_RegisterLocalizedFontString(megaFrame.title, "LOC_GAME_MEGA_BALL")
    megaFrame.bigBall = CreateFrame("Frame", nil, megaFrame)
    megaFrame.bigBall:SetSize(100, 100)
    megaFrame.bigBall:SetPoint("TOPLEFT", 60, -110)    
    local bbBg = megaFrame.bigBall:CreateTexture(nil, "BACKGROUND")
    bbBg:SetAllPoints()
    bbBg:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    bbBg:SetVertexColor(1, 0.8, 0)
    megaFrame.currentBallText = megaFrame.bigBall:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    megaFrame.currentBallText:SetPoint("CENTER", -15, 15)
    SetCustomFont(megaFrame.currentBallText, 40, "OUTLINE")
    megaFrame.currentBallText:SetText("?")
    megaFrame.multBox = CreateFrame("Frame", nil, megaFrame, "BackdropTemplate")
    megaFrame.multBox:SetSize(140, 40)
    megaFrame.multBox:SetPoint("TOP", megaFrame.bigBall, "BOTTOM", -15, -10)
    local mbBg = megaFrame.multBox:CreateTexture(nil, "BACKGROUND")
    mbBg:SetAllPoints(); mbBg:SetColorTexture(0.1, 0.05, 0.2, 0.9)
    local mbBorder = megaFrame.multBox:CreateTexture(nil, "BORDER")
    mbBorder:SetAllPoints(); mbBorder:SetColorTexture(1, 0, 1, 0.5)  
    megaFrame.multText = megaFrame.multBox:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    megaFrame.multText:SetPoint("CENTER")
    SetCustomFont(megaFrame.multText, 20, "OUTLINE")
    megaFrame.multText:SetTextColor(1, 0, 1)
    megaFrame.multText:SetText("MEGA: ?x")
    megaFrame.historyTitle = megaFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    megaFrame.historyTitle:SetPoint("TOPLEFT", megaFrame.multBox, "BOTTOMLEFT", -20, -15)
    SetCustomFont(megaFrame.historyTitle, 12, "OUTLINE")
    megaFrame.historyTitle:SetText(GC_L("LOC_2213"))
    megaFrame.historyBalls = {}
    for i = 1, 21 do
        local hf = CreateFrame("Frame", nil, megaFrame)
        hf:SetSize(26, 26)
        local row = math.floor((i-1) / 7)
        local col = (i-1) % 7
        hf:SetPoint("TOPLEFT", megaFrame.historyTitle, "BOTTOMLEFT", col * 28, -5 - (row * 28))      
        local hbg = hf:CreateTexture(nil, "BACKGROUND")
        hbg:SetAllPoints(); hbg:SetTexture("Interface\\Icons\\inv_misc_balloon_gold")        
        hf.val = hf:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        hf.val:SetPoint("CENTER")
        SetCustomFont(hf.val, 11, "OUTLINE")      
        megaFrame.historyBalls[i] = hf
        hf:Hide()
    end
    megaFrame.cardsContainer = CreateFrame("Frame", nil, megaFrame)
    megaFrame.cardsContainer:SetSize(380, 380)
    megaFrame.cardsContainer:SetPoint("RIGHT", -20, 65) 
    megaFrame.cards = {}
    local cardPositions = {
        {"TOPLEFT", 0, 0},
        {"TOPRIGHT", 0, 0},
        {"BOTTOMLEFT", 0, 0},
        {"BOTTOMRIGHT", 0, 0}
    }
    for cardIdx = 1, 4 do
        local cBg = CreateFrame("Frame", nil, megaFrame.cardsContainer, "BackdropTemplate")
        cBg:SetSize(185, 185)
        cBg:SetPoint(cardPositions[cardIdx][1], megaFrame.cardsContainer, cardPositions[cardIdx][1], cardPositions[cardIdx][2], cardPositions[cardIdx][3])

        local bgTex = cBg:CreateTexture(nil, "BACKGROUND")
        bgTex:SetAllPoints()
        bgTex:SetColorTexture(0.05, 0.05, 0.05, 0.9)
        local border = cBg:CreateTexture(nil, "BORDER")
        border:SetAllPoints()
        border:SetColorTexture(1, 0.8, 0, 0.3)

        cBg.cells = {}
        local cSize = 34
        local spacing = 2
        for r = 1, 5 do
            for c = 1, 5 do
                local idx = (r-1)*5 + c
                local f = CreateFrame("Frame", nil, cBg)
                f:SetSize(cSize, cSize)
                f:SetPoint("TOPLEFT", (c-1)*(cSize+spacing) + 4, -(r-1)*(cSize+spacing) - 4)

                f.bg = f:CreateTexture(nil, "BACKGROUND")
                f.bg:SetAllPoints()
                f.bg:SetColorTexture(0.15, 0.15, 0.15, 1)

                f.val = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
                f.val:SetPoint("CENTER")
                SetCustomFont(f.val, 13, "OUTLINE") 

                f.isMatched = false
                cBg.cells[idx] = f
            end
        end
        megaFrame.cards[cardIdx] = cBg
    end

    local isPlaying = false
    local numActiveCards = 4

    megaFrame.resultText = megaFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    megaFrame.resultText:SetPoint("BOTTOM", 0, 150)
    SetCustomFont(megaFrame.resultText, 16, "OUTLINE")
    megaFrame.resultText:SetText(GC_L("LOC_2244"))

    megaFrame.cardSelectorText = megaFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    megaFrame.cardSelectorText:SetPoint("BOTTOM", 0, 120)
    SetCustomFont(megaFrame.cardSelectorText, 12, "OUTLINE")
    megaFrame.cardSelectorText:SetText(GC_L("LOC_2249"))

    megaFrame.cardBtns = {}
    for i=1, 4 do
        local btn = CreateModernButton(megaFrame, i .. GC_L("LOC_MANUAL_TICKET_COUNT_SUFFIX"), 50, 25)
        btn:SetPoint("BOTTOM", (i - 2.5) * 55, 90) 
        btn:SetScript("OnClick", function()
            if not isPlaying then
                numActiveCards = i
                megaFrame.UpdateCardSelection()
            end
        end)
        megaFrame.cardBtns[i] = btn
    end

    megaFrame.actionBtn = CreateLocalizedButton(megaFrame, "LOC_2253", 260, 35)
    megaFrame.actionBtn:SetPoint("BOTTOM", 0, 50) 

    function megaFrame.UpdateCardSelection()
        for i=1, 4 do
            if i <= numActiveCards then
                megaFrame.cards[i]:Show()
            else
                megaFrame.cards[i]:Hide()
            end
            
            if i == numActiveCards then
                megaFrame.cardBtns[i].bg:SetColorTexture(0.2, 0.6, 0.2, 0.9)
            else
                megaFrame.cardBtns[i].bg:SetColorTexture(0.15, 0.15, 0.15, 0.9)
            end
        end
        megaFrame.actionBtn:SetText(numActiveCards .. GC_L("LOC_2255") .. (numActiveCards * 50) .. ")")
    end

    megaFrame.RefreshLanguage = function()
        for i=1, 4 do
            if megaFrame.cardBtns[i] then
                megaFrame.cardBtns[i]:SetText(i .. GC_L("LOC_MANUAL_TICKET_COUNT_SUFFIX"))
            end
        end
        if not isPlaying then
            megaFrame.UpdateCardSelection()
        end
    end

    megaFrame.paytable = megaFrame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    megaFrame.paytable:SetPoint("BOTTOMRIGHT", megaFrame.cardsContainer, "TOPRIGHT", 0, 5)
    SetCustomFont(megaFrame.paytable, 10, "OUTLINE")
    megaFrame.paytable:SetJustifyH("RIGHT")
    megaFrame.paytable:SetText(GC_L("LOC_2263"))

    local winLines = {
        {1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}, {16,17,18,19,20}, {21,22,23,24,25},
        {1,6,11,16,21}, {2,7,12,17,22}, {3,8,13,18,23}, {4,9,14,19,24}, {5,10,15,20,25},
        {1,7,13,19,25}, {5,9,13,17,21}
    }

    local function GenerateCard()
        for cardIdx = 1, 4 do
            local cols = {{},{},{},{},{}}
            for c=1,5 do
                local pool = {}
                local minV = (c-1)*9 + 1
                local maxV = c*9
                for v=minV, maxV do table.insert(pool, v) end
                for i=#pool, 2, -1 do local j=math.random(i); pool[i],pool[j]=pool[j],pool[i] end
                for r=1,5 do table.insert(cols[c], pool[r]) end
            end

            for r=1, 5 do
                for c=1, 5 do
                    local idx = (r-1)*5 + c
                    local cell = megaFrame.cards[cardIdx].cells[idx]
                    cell.isMatched = false
                    cell.bg:SetColorTexture(0.15, 0.15, 0.15, 1)
                    
                    if idx == 13 then
                        cell.val:SetText("*")
                        cell.val:SetTextColor(1, 0.8, 0)
                        cell.isMatched = true 
                        cell.bg:SetColorTexture(0.2, 0.2, 0.2, 1)
                    else
                        cell.val:SetText(cols[c][r])
                        cell.val:SetTextColor(1, 1, 1) 
                    end
                end
            end
        end
    end

    local function HighlightNearMisses()
        local needsHighlight = false
        for cardIdx = 1, numActiveCards do
            for _, l in ipairs(winLines) do
                local matchCount, missingIdx = 0, nil
                for _, idx in ipairs(l) do
                    if megaFrame.cards[cardIdx].cells[idx].isMatched then matchCount = matchCount + 1 else missingIdx = idx end
                end
                if matchCount == 4 and missingIdx then
                    megaFrame.cards[cardIdx].cells[missingIdx].bg:SetColorTexture(0, 0.5, 1, 0.9)
                    megaFrame.cards[cardIdx].cells[missingIdx].val:SetTextColor(1, 1, 1) 
                    needsHighlight = true
                end
            end
        end
        return needsHighlight
    end

    local function CheckPayout(megaMultiplier, megaBallNum)
        local totalWin = 0
        local totalLines = 0
        local anyMegaWin = false

        for cardIdx = 1, numActiveCards do
            local lines = 0
            local isMegaWin = false

            for _, l in ipairs(winLines) do
                local matchCount = 0
                local hasMegaInLine = false
                for _, idx in ipairs(l) do
                    if megaFrame.cards[cardIdx].cells[idx].isMatched then 
                        matchCount = matchCount + 1 
                        if tonumber(megaFrame.cards[cardIdx].cells[idx].val:GetText()) == megaBallNum then hasMegaInLine = true end
                    end
                end
                if matchCount == 5 then 
                    lines = lines + 1 
                    if hasMegaInLine then isMegaWin = true end
                    for _, idx in ipairs(l) do
                        if isMegaWin then 
                            megaFrame.cards[cardIdx].cells[idx].bg:SetColorTexture(0.8, 0, 0.8, 1) 
                        else 
                            megaFrame.cards[cardIdx].cells[idx].bg:SetColorTexture(0.2, 0.8, 0.2, 1) 
                        end
                        megaFrame.cards[cardIdx].cells[idx].val:SetTextColor(1, 1, 1)
                    end
                end
            end

            local baseWin = 0
            if lines == 1 then baseWin = 50
            elseif lines == 2 then baseWin = 200
            elseif lines == 3 then baseWin = 1000
            elseif lines == 4 then baseWin = 5000
            elseif lines >= 5 then baseWin = 20000 end

            if baseWin > 0 then
                totalLines = totalLines + lines
                if isMegaWin then
                    anyMegaWin = true
                    totalWin = totalWin + (baseWin * megaMultiplier)
                else
                    totalWin = totalWin + baseWin
                end
            end
        end

        local totalBet = numActiveCards * 50

        if totalWin > 0 then
            if anyMegaWin then
                megaFrame.resultText:SetText(GC_L("LOC_2265") .. totalLines .. GC_L("LOC_2266") .. totalWin .. GC_L("LOC_2267"))
                PlayCasinoSound(8440)
                AnnounceGameWin("Mega Ball ("..totalLines.." vonal, MEGA)", totalWin)
            else
                megaFrame.resultText:SetText(GC_L("LOC_2270") .. totalLines .. GC_L("LOC_2271") .. totalWin .. GC_L("LOC_2272"))
                PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                AnnounceGameWin("Mega Ball ("..totalLines.." vonal)", totalWin)
            end
            UpdatePlayChips(totalWin)
            AddChipTransaction(CleanName(UnitName("player")), totalWin, "Mega Ball")
        else
            local ticketStr = numActiveCards > 1 and GC_L("LOC_2277") .. numActiveCards .. GC_L("LOC_2278") or GC_L("LOC_2279")
            megaFrame.resultText:SetText("|cFFFF0000" .. ticketStr .. GC_L("LOC_2281"))
            AddChipTransaction(CleanName(UnitName("player")), -totalBet, "Mega Ball")
        end
    end

    megaFrame.actionBtn:SetScript("OnClick", function()
        if isPlaying then return end
        
        local totalBet = numActiveCards * 50
        if playChips < totalBet then 
            megaFrame.resultText:SetText(GC_L("LOC_2285") .. numActiveCards .. GC_L("LOC_2286") .. totalBet .. GC_L("LOC_2287"))
            return 
        end
        
        UpdatePlayChips(-totalBet)
        isPlaying = true
        megaFrame.actionBtn:Disable()
        for i=1, 4 do megaFrame.cardBtns[i]:Disable() end

        megaFrame.multText:SetText("MEGA: ?x")
        megaFrame.multText:SetTextColor(1, 1, 1)
        megaFrame.resultText:SetText(GC_L("LOC_2289"))
        
        for i=1, 21 do megaFrame.historyBalls[i]:Hide() end
        GenerateCard()

        local drawPool = {}
        for i=1, 45 do table.insert(drawPool, i) end
        for i = #drawPool, 2, -1 do local j = math.random(i); drawPool[i], drawPool[j] = drawPool[j], drawPool[i] end

        local drawnCount = 0
        local megaMultiplier = 1

        C_Timer.NewTicker(0.6, function(ticker1)
            drawnCount = drawnCount + 1
            local currentNum = drawPool[drawnCount]

            megaFrame.currentBallText:SetText(currentNum)
            megaFrame.historyTitle:SetText(GC_L("LOC_2290") .. drawnCount .. "):")
            
            megaFrame.historyBalls[drawnCount]:Show()
            megaFrame.historyBalls[drawnCount].val:SetText(currentNum)
            megaFrame.historyBalls[drawnCount].val:SetTextColor(1, 1, 1) 
            PlaySound(856)

            for cardIdx = 1, numActiveCards do
                for i=1, 25 do
                    if i ~= 13 and tonumber(megaFrame.cards[cardIdx].cells[i].val:GetText()) == currentNum then
                        megaFrame.cards[cardIdx].cells[i].isMatched = true
                        megaFrame.cards[cardIdx].cells[i].bg:SetColorTexture(0.8, 0.6, 0, 1) 
                        megaFrame.cards[cardIdx].cells[i].val:SetTextColor(1, 1, 1)
                    end
                end
            end

            if drawnCount == 20 then
                ticker1:Cancel()
                
                local needsHighlight = HighlightNearMisses()
                if needsHighlight then
                    megaFrame.resultText:SetText(GC_L("LOC_2292"))
                else
                    megaFrame.resultText:SetText(GC_L("LOC_2293"))
                end

                PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
                local pMults = {5, 5, 5, 10, 10, 12, 15, 20, 25, 50, 100}
                local spinTick = 0
                
                C_Timer.NewTicker(0.12, function(ticker2)
                    spinTick = spinTick + 1
                    megaFrame.multText:SetText("MEGA: " .. pMults[math.random(#pMults)] .. "x")
                    
                    if spinTick >= 25 then
                        ticker2:Cancel()
                        local r = math.random(1, 100)
                        if r > 98 then megaMultiplier = 100
                        elseif r > 90 then megaMultiplier = 50
                        elseif r > 75 then megaMultiplier = 25
                        elseif r > 50 then megaMultiplier = 15
                        elseif r > 25 then megaMultiplier = 10
                        else megaMultiplier = 5 end
                        
                        megaFrame.multText:SetText("MEGA: " .. megaMultiplier .. "x")
                        megaFrame.multText:SetTextColor(1, 0, 1)
                        megaFrame.resultText:SetText(GC_L("LOC_2299"))
                        PlaySound(856)

                        C_Timer.After(2.5, function()
                            local megaNum = drawPool[21]
                            megaFrame.currentBallText:SetText(megaNum)
                            megaFrame.currentBallText:SetTextColor(1, 0, 1)
                            
                            megaFrame.historyTitle:SetText(GC_L("LOC_2300"))
                            megaFrame.historyBalls[21]:Show()
                            megaFrame.historyBalls[21].val:SetText(megaNum)
                            megaFrame.historyBalls[21].val:SetTextColor(1, 1, 1)
                            
                            PlayCasinoSound(SOUNDKIT.RAID_WARNING)

                            for cardIdx = 1, numActiveCards do
                                for i=1, 25 do
                                    if i ~= 13 and tonumber(megaFrame.cards[cardIdx].cells[i].val:GetText()) == megaNum then
                                        megaFrame.cards[cardIdx].cells[i].isMatched = true
                                        megaFrame.cards[cardIdx].cells[i].bg:SetColorTexture(1, 0, 1, 1) 
                                        megaFrame.cards[cardIdx].cells[i].val:SetTextColor(1, 1, 1)
                                    end
                                end
                            end

                            CheckPayout(megaMultiplier, megaNum)
                            
                            isPlaying = false
                            megaFrame.actionBtn:Enable()
                            for i=1, 4 do megaFrame.cardBtns[i]:Enable() end
                            megaFrame.UpdateCardSelection() 
                            megaFrame.currentBallText:SetTextColor(1, 1, 1)
                        end)
                    end
                end, 25)
            end
        end, 20)
    end)
    
    megaFrame.UpdateCardSelection()
end

local olympusFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); olympusFrame:SetAllPoints(); olympusFrame:Hide()
do
    olympusFrame.title = olympusFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    olympusFrame.title:SetPoint("TOP", 0, -90); SetCustomFont(olympusFrame.title, 22, "OUTLINE"); GC_RegisterLocalizedFontString(olympusFrame.title, "LOC_GAME_GATES_OF_VOIDSPIRE_SLOT")

    local ROWS, COLS = 5, 6
    local CELL_SIZE = 40
    olympusFrame.grid = CreateFrame("Frame", nil, olympusFrame, "BackdropTemplate")
    olympusFrame.grid:SetSize(COLS * (CELL_SIZE + 2) + 14, ROWS * (CELL_SIZE + 2) + 14)
    olympusFrame.grid:SetPoint("CENTER", 0, 40)
    olympusFrame.grid:SetClipsChildren(true)   
    olympusFrame.gridBg = olympusFrame.grid:CreateTexture(nil, "BACKGROUND")
    olympusFrame.gridBg:SetAllPoints(); olympusFrame.gridBg:SetColorTexture(0.02, 0, 0.05, 0.95)
    olympusFrame.xalScene = CreateFrame("ModelScene", nil, olympusFrame)
    olympusFrame.xalScene:SetSize(350, 450)
    olympusFrame.xalScene:SetPoint("CENTER", olympusFrame.grid, "RIGHT", 80, 0)
    olympusFrame.xalScene:SetFrameLevel(olympusFrame.grid:GetFrameLevel() + 5)
    olympusFrame.xalActor = olympusFrame.xalScene:CreateActor()
    olympusFrame.xalActor:SetModelByFileID(5159886)
    olympusFrame.xalActor:SetYaw(math.pi) 
    olympusFrame.xalActor:SetPosition(6, 0.5, -1) 
    olympusFrame.xalActor:SetScale(0.9) 
    olympusFrame.xalActor:SetAnimation(0)

    local function XalCast()
        olympusFrame.xalActor:SetAnimation(1138)
        C_Timer.After(2, function() olympusFrame.xalActor:SetAnimation(0) end)
    end
    local symbolIcons = {
        "Interface\\Icons\\inv_misc_gem_amethyst_02", "Interface\\Icons\\inv_misc_gem_topaz_02",    
        "Interface\\Icons\\inv_misc_gem_emerald_02", "Interface\\Icons\\inv_misc_gem_ruby_02",     
        "Interface\\Icons\\inv_helmet_74", "Interface\\Icons\\inv_sword_2h_artifactashbringer_d_01", 
        "FS_SYMBOL", "Interface\\Icons\\inv_misc_ornament_01" 
    }
    local infoPanel = CreateFrame("Frame", nil, olympusFrame, "BackdropTemplate")
    infoPanel:SetSize(140, 220); infoPanel:SetPoint("RIGHT", olympusFrame.grid, "LEFT", -20, 0)
    infoPanel:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = {left = 4, right = 4, top = 4, bottom = 4}})
    infoPanel:SetBackdropColor(0, 0, 0, 0.7); infoPanel:SetBackdropBorderColor(0.6, 0.2, 0.9, 0.8)
    
    local infoTitle = infoPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    infoTitle:SetPoint("TOP", 0, -10); infoTitle:SetText(GC_L("LOC_2331")); SetCustomFont(infoTitle, 10)
    
    for i=1, 6 do
        local row = CreateFrame("Frame", nil, infoPanel)
        row:SetSize(120, 20); row:SetPoint("TOPLEFT", 10, -30 - (i-1)*22)
        local icon = row:CreateTexture(nil, "ARTWORK"); icon:SetSize(16, 16); icon:SetPoint("LEFT", 0, 0); icon:SetTexture(symbolIcons[i])
        local text = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        text:SetPoint("LEFT", 20, 0); SetCustomFont(text, 10)
        if i == 6 then text:SetText("75 / 150 / 300")
        elseif i == 5 then text:SetText("40 / 75 / 150")
        else text:SetText("5 / 15 / 25") end
    end
    local fsInfo = infoPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    fsInfo:SetPoint("BOTTOM", infoPanel, "BOTTOM", 0, 15) 
    SetCustomFont(fsInfo, 10, "OUTLINE")
    fsInfo:SetTextColor(1, 0.8, 0) 
    fsInfo:SetText(GC_L("LOC_2347"))
    
    olympusFrame.cells = {}
    for r = 1, ROWS do
        olympusFrame.cells[r] = {}
        for c = 1, COLS do
            local f = CreateFrame("Frame", nil, olympusFrame.grid)
            f:SetSize(CELL_SIZE, CELL_SIZE)
            f:SetPoint("TOPLEFT", (c-1)*(CELL_SIZE+2) + 8, -(r-1)*(CELL_SIZE+2) - 8)
            f.tex = f:CreateTexture(nil, "ARTWORK"); f.tex:SetAllPoints()
            f.glow = f:CreateTexture(nil, "OVERLAY"); f.glow:SetAllPoints(); f.glow:SetTexture("Interface\\Buttons\\CheckButtonGlow"); f.glow:SetAlpha(0)
            f.fsText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
            f.fsText:SetPoint("CENTER", 0, 0); SetCustomFont(f.fsText, 18, "OUTLINE"); f.fsText:SetTextColor(1, 0.8, 0); f.fsText:SetText("FS"); f.fsText:Hide()
            f.multText = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            f.multText:SetPoint("CENTER", 0, 0); SetCustomFont(f.multText, 14, "OUTLINE"); f.multText:SetTextColor(1, 1, 1); f.multText:Hide()
            
            f.dropAnim = f:CreateAnimationGroup()
            f.instUp = f.dropAnim:CreateAnimation("Translation")
            f.instUp:SetOrder(1); f.instUp:SetDuration(0)
            f.dropDown = f.dropAnim:CreateAnimation("Translation")
            f.dropDown:SetOrder(2); f.dropDown:SetSmoothing("IN")

            olympusFrame.cells[r][c] = f
        end
    end

    olympusFrame.accumWinText = olympusFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    olympusFrame.accumWinText:SetPoint("TOP", olympusFrame.grid, "BOTTOM", 0, -10)
    SetCustomFont(olympusFrame.accumWinText, 24, "OUTLINE"); olympusFrame.accumWinText:SetTextColor(1, 1, 1); olympusFrame.accumWinText:SetText("")
    olympusFrame.multDisplay = olympusFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    olympusFrame.multDisplay:SetPoint("BOTTOM", olympusFrame.grid, "TOP", 90, 0)
    SetCustomFont(olympusFrame.multDisplay, 45, "OUTLINE") 
    olympusFrame.multDisplay:SetTextColor(0.8, 0.4, 1, 1)
    olympusFrame.bonusScroll = olympusFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    olympusFrame.bonusScroll:SetPoint("BOTTOM", olympusFrame.grid, "TOP", -60, 15); SetCustomFont(olympusFrame.bonusScroll, 20, "OUTLINE")
    olympusFrame.spinBtn = CreateLocalizedButton(olympusFrame, "LOC_2381", 180, 40)
    olympusFrame.spinBtn:SetPoint("BOTTOM", 0, 65); olympusFrame.spinBtn.bg:SetColorTexture(0.4, 0, 0.6, 0.9)
    local isSpinning, isFreeSpins = false, false
    local freeSpinsLeft, globalMult, bonusTotal = 0, 0, 0
    local spinWin, spinMult = 0, 0
    local function UpdateCellVisual(r, c, symbol, mValue)
        local cell = olympusFrame.cells[r][c]
        cell.currentSymbol = symbol; cell.currentMult = mValue or 0; cell.multText:Hide()
        if symbol == "FS_SYMBOL" then cell.tex:SetAlpha(0); cell.fsText:Show(); cell.glow:SetVertexColor(1, 0.5, 0); cell.glow:SetAlpha(0.6)
        elseif symbol == symbolIcons[8] then cell.tex:SetTexture(symbol); cell.tex:SetAlpha(1); cell.fsText:Hide(); cell.glow:SetVertexColor(0.8, 0, 1); cell.glow:SetAlpha(0.8); cell.multText:SetText(cell.currentMult .. "x"); cell.multText:Show()
        else cell.tex:SetTexture(symbol); cell.tex:SetAlpha(1); cell.fsText:Hide(); cell.glow:SetAlpha(0) end
    end

    local function GetRandomSymbol()
        local r = math.random(1, 1000)
        if r > 990 then 
            local mR = math.random(1, 1000)
            local mVal = 2 
            if mR == 1000 then mVal = 200 
            elseif mR > 990 then mVal = 50 
            elseif mR > 950 then mVal = 25 
            elseif mR > 850 then mVal = 8  
            elseif mR > 700 then mVal = 5
            else mVal = 2 end
            return symbolIcons[8], mVal 
        elseif r > 972 then return "FS_SYMBOL"
        elseif r > 950 then return symbolIcons[6] 
        elseif r > 910 then return symbolIcons[5] 
        else return symbolIcons[math.random(1, 4)] end 
    end

    local function ApplyGravity()
        local changed = false
        for c = 1, COLS do
            for r = ROWS, 2, -1 do
                if olympusFrame.cells[r][c].tex:GetAlpha() == 0 and not olympusFrame.cells[r][c].fsText:IsShown() then
                    local aboveCell = olympusFrame.cells[r-1][c]
                    if aboveCell.tex:GetAlpha() > 0 or aboveCell.fsText:IsShown() then
                        UpdateCellVisual(r, c, aboveCell.currentSymbol, aboveCell.currentMult)
                        if olympusFrame.cells[r][c].dropAnim then
                            olympusFrame.cells[r][c].instUp:SetOffset(0, CELL_SIZE + 2)
                            olympusFrame.cells[r][c].dropDown:SetOffset(0, -(CELL_SIZE + 2))
                            olympusFrame.cells[r][c].dropDown:SetDuration(0.15)
                            olympusFrame.cells[r][c].dropAnim:Stop()
                            olympusFrame.cells[r][c].dropAnim:Play()
                        end

                        aboveCell.tex:SetAlpha(0); aboveCell.fsText:Hide(); aboveCell.glow:SetAlpha(0); aboveCell.multText:Hide()
                        changed = true
                    end
                end
            end
            if olympusFrame.cells[1][c].tex:GetAlpha() == 0 and not olympusFrame.cells[1][c].fsText:IsShown() then
                local sym, mVal = GetRandomSymbol()
                UpdateCellVisual(1, c, sym, mVal)

                if olympusFrame.cells[1][c].dropAnim then
                    olympusFrame.cells[1][c].instUp:SetOffset(0, CELL_SIZE + 2)
                    olympusFrame.cells[1][c].dropDown:SetOffset(0, -(CELL_SIZE + 2))
                    olympusFrame.cells[1][c].dropDown:SetDuration(0.15)
                    olympusFrame.cells[1][c].dropAnim:Stop()
                    olympusFrame.cells[1][c].dropAnim:Play()
                end
                
                changed = true
            end
        end
        if changed then C_Timer.After(0.16, ApplyGravity) else C_Timer.After(0.3, olympusFrame.CheckWins) end
    end

    function olympusFrame.CheckWins()
        local counts = {}
        local scatterCount = 0
        local multipliersInSpin = {}
        for r=1,ROWS do for c=1,COLS do 
            local sym = olympusFrame.cells[r][c].currentSymbol
            if sym == "FS_SYMBOL" then scatterCount = scatterCount + 1 end
            if sym == symbolIcons[8] then table.insert(multipliersInSpin, {r = r, c = c, val = olympusFrame.cells[r][c].currentMult}) end
            counts[sym] = (counts[sym] or 0) + 1
        end end

        local won = false
        for sym, count in pairs(counts) do
            if count >= 10 and sym ~= "FS_SYMBOL" and sym ~= symbolIcons[8] then
                won = true
                for r=1,ROWS do for c=1,COLS do
                    if olympusFrame.cells[r][c].currentSymbol == sym then
                        olympusFrame.cells[r][c].tex:SetAlpha(0); olympusFrame.cells[r][c].glow:SetAlpha(0)
                    end
                end end
                local p = (sym == symbolIcons[6]) and (count >= 15 and 300 or (count >= 12 and 150 or 75)) or (sym == symbolIcons[5] and (count >= 15 and 150 or (count >= 12 and 75 or 40)) or (count >= 15 and 25 or (count >= 12 and 15 or 5)))
                spinWin = spinWin + p
            end
        end

        if won and #multipliersInSpin > 0 then
            XalCast() 
            local turnMult = 0
            for _, mData in ipairs(multipliersInSpin) do turnMult = turnMult + mData.val; local cell = olympusFrame.cells[mData.r][mData.c]; cell.tex:SetAlpha(0); cell.glow:SetAlpha(0); cell.multText:Hide() end
            spinMult = spinMult + turnMult
            if isFreeSpins then globalMult = globalMult + turnMult end
            olympusFrame.multDisplay:SetText("x" .. (isFreeSpins and globalMult or spinMult))
            PlaySound(23197, "Master")
        end

        if won then
            PlaySound(1210, "Master"); olympusFrame.accumWinText:SetText(spinWin); C_Timer.After(0.5, ApplyGravity)
        else
            local fM = 1
            if isFreeSpins then
                if spinMult > 0 then fM = globalMult else fM = 1 end
            else
                fM = spinMult > 0 and spinMult or 1
            end
            local total = math.floor(spinWin * fM)

            local delayTime = 0.15
            
            if total > 0 then
                UpdatePlayChips(total); bonusTotal = bonusTotal + total
                AddChipTransaction(CleanName(UnitName("player")), total, "Gates of Voidspire")
                olympusFrame.accumWinText:SetTextColor(0.8, 0.4, 1); olympusFrame.accumWinText:SetText(spinWin .. " x " .. fM .. " = " .. total)
                PlaySound(120, "Master")
                
                delayTime = 1.0
            end
            
            C_Timer.After(delayTime, function() olympusFrame.accumWinText:SetTextColor(1, 1, 1); olympusFrame.Finalize(scatterCount) end)
        end
    end

    function olympusFrame.Finalize(scatters)
        if scatters >= 4 and not isFreeSpins then
            isFreeSpins = true
            freeSpinsLeft = 10
            globalMult = 0
            bonusTotal = 0
            spinMult = 0 
            olympusFrame.multDisplay:SetText("") 
            
            olympusFrame.gridBg:SetColorTexture(0.2, 0, 0.3, 0.95)
            C_Timer.After(1.5, olympusFrame.DoSpin)
        elseif isFreeSpins and freeSpinsLeft > 0 then
            C_Timer.After(0.5, olympusFrame.DoSpin)
        else
            if isFreeSpins then 
                AnnounceGameWin("Gates of Voidspire", bonusTotal)
                olympusFrame.gridBg:SetColorTexture(0.02, 0, 0.05, 0.95)
                olympusFrame.bonusScroll:SetText("")
            end
            isFreeSpins = false
            isSpinning = false
            spinMult = 0
            olympusFrame.spinBtn:Enable()
        end
    end

    function olympusFrame.DoSpin()
        spinWin, spinMult = 0, 0; olympusFrame.accumWinText:SetText("")
        if isFreeSpins then
            freeSpinsLeft = freeSpinsLeft - 1; olympusFrame.bonusScroll:SetText(GC_L("LOC_2400") .. freeSpinsLeft .. "|r")
        else
            if playChips < 50 then isSpinning = false; olympusFrame.spinBtn:Enable(); return end
            UpdatePlayChips(-50); olympusFrame.multDisplay:SetText(""); olympusFrame.bonusScroll:SetText("")
            PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        end

        for r=1,ROWS do 
            for c=1,COLS do 
                olympusFrame.cells[r][c].tex:SetAlpha(0)
                olympusFrame.cells[r][c].fsText:Hide()
                olympusFrame.cells[r][c].glow:SetAlpha(0)
                olympusFrame.cells[r][c].multText:Hide() 
            end 
        end

        for c = 1, COLS do
            C_Timer.After((c - 1) * 0.1, function()
                for r = ROWS, 1, -1 do 
                    C_Timer.After((ROWS - r) * 0.08, function()
                        local cell = olympusFrame.cells[r][c]
                        local sym, mVal = GetRandomSymbol()
                        UpdateCellVisual(r, c, sym, mVal)
                        
                        if cell.dropAnim then
                            local dropDistance = r * (CELL_SIZE + 2)
                            cell.instUp:SetOffset(0, dropDistance)
                            cell.dropDown:SetOffset(0, -dropDistance)
                            cell.dropDown:SetDuration(r * 0.06) 
                            
                            cell.dropAnim:Stop()
                            cell.dropAnim:Play()
                        end
                    end)
                end
                
                if c == COLS then
                    C_Timer.After(0.7, olympusFrame.CheckWins) 
                end
            end)
        end
    end
    
    function olympusFrame.ResetTable()
        spinWin, spinMult, bonusTotal, globalMult = 0, 0, 0, 0
        isSpinning, isFreeSpins = false, false
        olympusFrame.accumWinText:SetText("")
        olympusFrame.multDisplay:SetText("")
        olympusFrame.bonusScroll:SetText("")
        olympusFrame.spinBtn:Enable()
        for r=1,ROWS do for c=1,COLS do 
            olympusFrame.cells[r][c].tex:SetAlpha(0)
            olympusFrame.cells[r][c].fsText:Hide()
            olympusFrame.cells[r][c].glow:SetAlpha(0)
            olympusFrame.cells[r][c].multText:Hide() 
        end end
        olympusFrame.gridBg:SetColorTexture(0.02, 0, 0.05, 0.95)
    end

    olympusFrame.spinBtn:SetScript("OnClick", function() if not isSpinning then isSpinning = true; olympusFrame.spinBtn:Disable(); olympusFrame.DoSpin() end end)
end
local chickenRoadFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); chickenRoadFrame:SetAllPoints(); chickenRoadFrame:Hide()
do
    chickenRoadFrame.title = chickenRoadFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    chickenRoadFrame.title:SetPoint("TOP", 0, -75)
    SetCustomFont(chickenRoadFrame.title, 20, "OUTLINE")
    GC_RegisterLocalizedFontString(chickenRoadFrame.title, "LOC_GAME_CHICKEN_ROAD")

    chickenRoadFrame.statusText = chickenRoadFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    chickenRoadFrame.statusText:SetPoint("TOP", chickenRoadFrame.title, "BOTTOM", 0, -8)
    SetCustomFont(chickenRoadFrame.statusText, 14, "OUTLINE")
    chickenRoadFrame.statusText:SetText(GC_L("LOC_2429"))

    chickenRoadFrame.grid = CreateFrame("Frame", nil, chickenRoadFrame, "BackdropTemplate")
    chickenRoadFrame.grid:SetSize(440, 110); chickenRoadFrame.grid:SetPoint("CENTER", 0, 25)
    chickenRoadFrame.grid:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground"})
    chickenRoadFrame.grid:SetBackdropColor(0.12, 0.12, 0.12, 1)

    for i=1, 7 do
        local laneX = i * 52 + 11
        for j=0, 5 do
            local dash = chickenRoadFrame.grid:CreateTexture(nil, "ARTWORK")
            dash:SetSize(2, 10); dash:SetPoint("TOPLEFT", chickenRoadFrame.grid, "TOPLEFT", laneX, -j*18 - 5)
            dash:SetColorTexture(1, 1, 1, 0.3)
        end
    end

    local startLine = chickenRoadFrame.grid:CreateTexture(nil, "ARTWORK")
    startLine:SetSize(3, 110); startLine:SetPoint("LEFT", 5, 0); startLine:SetColorTexture(1, 0.8, 0, 0.6)
    local endLine = chickenRoadFrame.grid:CreateTexture(nil, "ARTWORK")
    endLine:SetSize(4, 110); endLine:SetPoint("RIGHT", -5, 0); endLine:SetColorTexture(1, 1, 1, 0.3)

    chickenRoadFrame.tiles = {}
    chickenRoadFrame.currentStep = 1; chickenRoadFrame.currentBet = 0; chickenRoadFrame.isActive = false; chickenRoadFrame.difficulty = 2 

    local diffSettings = {
        [1] = {
            localeKey = "LOC_2441",
            chances = {80, 75, 70, 60, 55, 45, 40, 30},
            mults = {1.05, 1.25, 1.55, 2.10, 2.90, 4.20, 6.50, 9.80}
        },
        [2] = {
            localeKey = "LOC_2442",
            chances = {65, 55, 45, 35, 25, 15, 8, 5},
            mults = {1.20, 1.65, 2.50, 4.80, 9.50, 22.0, 55.0, 100.0}
        },
        [3] = {
            localeKey = "LOC_2443",
            chances = {60, 35, 20, 10, 5, 3, 2, 1},
            mults = {1.45, 3.20, 12.0, 35.0, 85.0, 200.0, 300.0, 500.0}
        }
    }

    local function UpdateDifficultyUI()
        local data = diffSettings[chickenRoadFrame.difficulty]
        for c = 1, 8 do
            chickenRoadFrame.tiles[c].multText:SetText(data.mults[c].."x")
            chickenRoadFrame.tiles[c].chanceText:SetText(data.chances[c].."%")
        end
        for i=1, 3 do
            if chickenRoadFrame.difficulty == i then
                chickenRoadFrame.diffBtns[i].bg:SetColorTexture(0.2, 0.7, 0.2, 0.9)
            else
                chickenRoadFrame.diffBtns[i].bg:SetColorTexture(0.1, 0.1, 0.1, 0.9)
            end
        end
    end

    chickenRoadFrame.RefreshLanguage = function()
        UpdateDifficultyUI()
        if chickenRoadFrame.isActive and chickenRoadFrame.currentStep > 1 then
            local data = diffSettings[chickenRoadFrame.difficulty]
            local curWin = math.floor(chickenRoadFrame.currentBet * data.mults[chickenRoadFrame.currentStep - 1])
            chickenRoadFrame.cashoutBtn:SetText(GC_L("LOC_2497")..curWin..")")
        elseif chickenRoadFrame.isActive then
            chickenRoadFrame.cashoutBtn:SetText(GC_L("LOC_2504"))
            chickenRoadFrame.statusText:SetText(GC_L("LOC_2503"))
        else
            chickenRoadFrame.statusText:SetText(GC_L("LOC_2429"))
        end
    end

    chickenRoadFrame.animChicken = CreateFrame("Frame", nil, chickenRoadFrame)
    chickenRoadFrame.animChicken:SetSize(32, 32); chickenRoadFrame.animChicken:SetFrameStrata("FULLSCREEN_DIALOG"); chickenRoadFrame.animChicken:SetFrameLevel(9999) 
    chickenRoadFrame.animChicken.tex = chickenRoadFrame.animChicken:CreateTexture(nil, "OVERLAY")
    chickenRoadFrame.animChicken.tex:SetAllPoints(); chickenRoadFrame.animChicken.tex:SetTexture(135996); chickenRoadFrame.animChicken:Hide()

    local jumpAnimFrame = CreateFrame("Frame", nil, chickenRoadFrame)
    jumpAnimFrame:Hide()
    local jTimer, jDuration = 0, 0.45; local sX, sY, eX, eY
    jumpAnimFrame:SetScript("OnUpdate", function(self, elapsed)
        jTimer = jTimer + elapsed; local p = jTimer / jDuration; if p >= 1 then p = 1 end
        local cX = sX + (eX - sX) * p; local cY = sY + (eY - sY) * p + math.sin(p * math.pi) * 55 
        chickenRoadFrame.animChicken:SetPoint("CENTER", chickenRoadFrame.grid, "BOTTOMLEFT", cX, cY)
        if p == 1 then self:Hide(); if self.callback then self.callback() end end
    end)

    local function JumpChicken(fromC, toC, callback)
        chickenRoadFrame.animChicken:Show(); local function GetX(c) return (c-1)*52 + 42 end
        eX = GetX(toC); eY = 35
        if fromC == 0 then sX = GetX(1) - 45; sY = -15 else sX = GetX(fromC); sY = 35 end
        jTimer = 0; jumpAnimFrame.callback = callback; jumpAnimFrame:Show()
    end

    for c = 1, 8 do
        local btn = CreateFrame("Frame", nil, chickenRoadFrame.grid, "BackdropTemplate")
        btn:SetSize(50, 60); btn:SetPoint("LEFT", (c-1)*52 + 15, 5)
        btn:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
        btn:SetBackdropColor(0, 0, 0, 0); btn:SetBackdropBorderColor(1, 1, 1, 0.1)
        btn.icon = btn:CreateTexture(nil, "ARTWORK"); btn.icon:SetSize(32, 32); btn.icon:SetPoint("CENTER"); btn.icon:Hide()
        btn.multText = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); btn.multText:SetPoint("CENTER")
        SetCustomFont(btn.multText, 11, "OUTLINE")
        btn.chanceText = btn:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall"); btn.chanceText:SetPoint("TOP", btn, "BOTTOM", 0, -5)
        SetCustomFont(btn.chanceText, 10)
        chickenRoadFrame.tiles[c] = btn
    end

    chickenRoadFrame.diffBtns = {}
    local diffNames = {"LOC_2468", "LOC_2469", "LOC_2470"}
    for i=1, 3 do
        local b = CreateLocalizedButton(chickenRoadFrame, diffNames[i], 80, 25)
        b:SetPoint("BOTTOMLEFT", 100 + (i-1)*85, 115)
        b:SetScript("OnClick", function() if not chickenRoadFrame.isActive then chickenRoadFrame.difficulty = i; UpdateDifficultyUI() end end)
        chickenRoadFrame.diffBtns[i] = b
    end

    chickenRoadFrame.goBtn = CreateLocalizedButton(chickenRoadFrame, "LOC_MANUAL_GO", 100, 40)
    chickenRoadFrame.goBtn:SetPoint("TOP", chickenRoadFrame.grid, "BOTTOM", 0, -12); chickenRoadFrame.goBtn:Disable()

    chickenRoadFrame.betInput = CreateFrame("EditBox", nil, chickenRoadFrame, "InputBoxTemplate")
    chickenRoadFrame.betInput:SetSize(80, 30); chickenRoadFrame.betInput:SetPoint("BOTTOMLEFT", 100, 65)
    chickenRoadFrame.betInput:SetNumeric(true); chickenRoadFrame.betInput:SetText("50")
    chickenRoadFrame.betInput:SetAutoFocus(false)
    SetCustomFont(chickenRoadFrame.betInput, 14)
    chickenRoadFrame.betInput:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
    chickenRoadFrame.betInput:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
    chickenRoadFrame.startBtn = CreateLocalizedButton(chickenRoadFrame, "LOC_2482", 120, 35)
    chickenRoadFrame.startBtn:SetPoint("LEFT", chickenRoadFrame.betInput, "RIGHT", 20, 0)
    chickenRoadFrame.cashoutBtn = CreateLocalizedButton(chickenRoadFrame, "LOC_2485", 120, 35)
    chickenRoadFrame.cashoutBtn:SetPoint("LEFT", chickenRoadFrame.startBtn, "RIGHT", 10, 0); chickenRoadFrame.cashoutBtn:Disable()
    local function EndGame(won)
        chickenRoadFrame.isActive = false; chickenRoadFrame.startBtn:Enable(); chickenRoadFrame.goBtn:Disable(); chickenRoadFrame.cashoutBtn:Disable(); chickenRoadFrame.betInput:Enable()
        for i=1, 3 do chickenRoadFrame.diffBtns[i]:Enable() end
        if won and chickenRoadFrame.currentStep > 1 then
            local winAmt = math.floor(chickenRoadFrame.currentBet * diffSettings[chickenRoadFrame.difficulty].mults[chickenRoadFrame.currentStep - 1])
            UpdatePlayChips(winAmt); AddChipTransaction(CleanName(UnitName("player")), winAmt, "Chicken Road")
            chickenRoadFrame.statusText:SetText(GC_L("LOC_2490") .. winAmt .. GC_L("LOC_2491"))
            PlayCasinoSound(8440); AnnounceGameWin("Chicken Road ("..GC_L(diffSettings[chickenRoadFrame.difficulty].localeKey)..")", winAmt)
        elseif not won then
            chickenRoadFrame.statusText:SetText(GC_L("LOC_2494"))
            AddChipTransaction(CleanName(UnitName("player")), -chickenRoadFrame.currentBet, "Chicken Road"); PlaySound(856)
        end
    end

    function chickenRoadFrame.Step()
        chickenRoadFrame.goBtn:Disable(); chickenRoadFrame.cashoutBtn:Disable()
        local c = chickenRoadFrame.currentStep; local data = diffSettings[chickenRoadFrame.difficulty]; local roll = math.random(1, 100)
        JumpChicken(c - 1, c, function()
            chickenRoadFrame.tiles[c].multText:Hide(); chickenRoadFrame.tiles[c].icon:Show()
            if roll > data.chances[c] then
                chickenRoadFrame.tiles[c].icon:SetTexture(7636523); chickenRoadFrame.tiles[c]:SetBackdropColor(0.8, 0.1, 0.1, 0.6)
                chickenRoadFrame.animChicken:Hide(); EndGame(false)
            else
                chickenRoadFrame.tiles[c].icon:SetTexture(135996); chickenRoadFrame.tiles[c]:SetBackdropColor(0.1, 0.8, 0.1, 0.5)
                chickenRoadFrame.animChicken:Hide(); PlaySound(856); chickenRoadFrame.currentStep = c + 1
                if chickenRoadFrame.currentStep > 8 then EndGame(true) else
                    local curWin = math.floor(chickenRoadFrame.currentBet * data.mults[chickenRoadFrame.currentStep - 1])
                    chickenRoadFrame.cashoutBtn:SetText(GC_L("LOC_2497")..curWin..")")
                    chickenRoadFrame.goBtn:Enable(); chickenRoadFrame.cashoutBtn:Enable()
                    chickenRoadFrame.statusText:SetText(GC_L("LOC_2499"))
                    chickenRoadFrame.tiles[chickenRoadFrame.currentStep]:SetBackdropColor(1, 1, 1, 0.15)
                end
            end
        end)
    end

    chickenRoadFrame.goBtn:SetScript("OnClick", function() if chickenRoadFrame.isActive then chickenRoadFrame.Step() end end)
    chickenRoadFrame.cashoutBtn:SetScript("OnClick", function() if chickenRoadFrame.isActive and chickenRoadFrame.currentStep > 1 then EndGame(true) end end)
    chickenRoadFrame.startBtn:SetScript("OnClick", function()
        local bet = tonumber(chickenRoadFrame.betInput:GetText()) or 0
        if bet <= 0 or playChips < bet then return end
        UpdatePlayChips(-bet); chickenRoadFrame.currentBet = bet; chickenRoadFrame.isActive = true; chickenRoadFrame.currentStep = 1
        chickenRoadFrame.statusText:SetText(GC_L("LOC_2503"))
        chickenRoadFrame.startBtn:Disable(); chickenRoadFrame.betInput:Disable(); chickenRoadFrame.goBtn:Enable(); chickenRoadFrame.cashoutBtn:Disable() 
        for i=1, 3 do chickenRoadFrame.diffBtns[i]:Disable() end
        chickenRoadFrame.cashoutBtn:SetText(GC_L("LOC_2504")); chickenRoadFrame.animChicken:Hide()
        for c=1, 8 do 
            chickenRoadFrame.tiles[c].icon:Hide(); chickenRoadFrame.tiles[c].multText:Show()
            chickenRoadFrame.tiles[c]:SetBackdropColor(0, 0, 0, 0)
        end
        chickenRoadFrame.tiles[1]:SetBackdropColor(1, 1, 1, 0.15)
    end)

    UpdateDifficultyUI()
end

local crashFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); crashFrame:SetAllPoints(); crashFrame:Hide()
do
    crashFrame.title = crashFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    crashFrame.title:SetPoint("TOP", 0, -70)
    SetCustomFont(crashFrame.title, 20, "OUTLINE")
    crashFrame.title:SetText(GC_L("LOC_2510"))
    crashFrame.graphBg = crashFrame:CreateTexture(nil, "BACKGROUND")
    crashFrame.graphBg:SetSize(400, 240); crashFrame.graphBg:SetPoint("CENTER", 0, 20)
    crashFrame.graphBg:SetColorTexture(0.05, 0.08, 0.1, 0.9)

    for i=1, 4 do
        local hl = crashFrame:CreateTexture(nil, "BORDER")
        hl:SetSize(400, 1); hl:SetPoint("BOTTOM", crashFrame.graphBg, "BOTTOM", 0, i*48)
        hl:SetColorTexture(1, 1, 1, 0.1)
        local vl = crashFrame:CreateTexture(nil, "BORDER")
        vl:SetSize(1, 240); vl:SetPoint("LEFT", crashFrame.graphBg, "LEFT", i*80, 0)
        vl:SetColorTexture(1, 1, 1, 0.1)
    end

    crashFrame.multText = crashFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    crashFrame.multText:SetPoint("CENTER", crashFrame.graphBg, "CENTER", 0, 0)
    SetCustomFont(crashFrame.multText, 65, "OUTLINE")
    crashFrame.multText:SetText("1.00x")
    crashFrame.statusText = crashFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    crashFrame.statusText:SetPoint("TOP", crashFrame.graphBg, "BOTTOM", 0, -10)
    SetCustomFont(crashFrame.statusText, 16, "OUTLINE")
    crashFrame.statusText:SetText(GC_L("LOC_2530"))
    crashFrame.graphLine = crashFrame:CreateLine(nil, "OVERLAY")
    crashFrame.graphLine:SetThickness(4)
    crashFrame.graphLine:SetColorTexture(1, 0.8, 0, 0.8)
    crashFrame.graphLine:Hide()
    crashFrame.rocket = crashFrame:CreateTexture(nil, "OVERLAY")
    crashFrame.rocket:SetSize(32, 32)
    crashFrame.rocket:SetTexture("Interface\\Icons\\inv_zeppelinmount")
    crashFrame.rocket:SetPoint("BOTTOMLEFT", crashFrame.graphBg, "BOTTOMLEFT", 10, 10)
    crashFrame.rocket:Hide()
    crashFrame.history = {}
    crashFrame.historyText = crashFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    crashFrame.historyText:SetPoint("TOPLEFT", crashFrame.graphBg, "TOPLEFT", 5, -5)
    SetCustomFont(crashFrame.historyText, 12, "OUTLINE")
    crashFrame.historyText:SetText(GC_L("LOC_2541"))
    crashFrame.actionBtn = CreateLocalizedButton(crashFrame, "LOC_2542", 160, 40)
    crashFrame.actionBtn:SetPoint("BOTTOM", crashFrame.graphBg, "BOTTOM", 40, -80)
    crashFrame.betInput = CreateFrame("EditBox", nil, crashFrame, "InputBoxTemplate")
    crashFrame.betInput:SetSize(60, 30)
    crashFrame.betInput:SetPoint("RIGHT", crashFrame.actionBtn, "LEFT", -30, 0)
    crashFrame.betInput:SetNumeric(true)
    crashFrame.betInput:SetAutoFocus(false)
    crashFrame.betInput:SetText("50")
    SetCustomFont(crashFrame.betInput, 14) 
    local betLbl = crashFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    betLbl:SetPoint("BOTTOMLEFT", crashFrame.betInput, "TOPLEFT", 0, 2)
    SetCustomFont(betLbl, 10)
    GC_RegisterLocalizedFontString(betLbl, "LOC_2554")

    local isFlying = false
    local currentMult = 1.00
    local crashPoint = 1.00
    local currentBet = 0
    local ticker = nil
    local tickCount = 0

    local function GetCrashPoint()
        if math.random(1, 100) <= 4 then return 1.00 end 
        local r = math.random()
        local val = 1.00 / (1.00 - r)
        if val > 1000 then val = 1000 end 
        return math.floor(val * 100) / 100
    end

    local function UpdateHistory(val)
        table.insert(crashFrame.history, 1, val)
        if #crashFrame.history > 6 then table.remove(crashFrame.history, 7) end
        local str = GC_L("LOC_2555")
        for _, v in ipairs(crashFrame.history) do
            local color = (v < 1.5) and "|cFFFF0000" or ((v < 5.0) and "|cFFFFFF00" or "|cFF00FF00")
            str = str .. color .. string.format("%.2fx", v) .. "|r "
        end
        crashFrame.historyText:SetText(str)
    end

    local function EndCrash(cashedOut)
        isFlying = false
        
        if cashedOut then
            local winAmt = math.floor(currentBet * currentMult)
            UpdatePlayChips(winAmt)
			AddChipTransaction(CleanName(UnitName("player")), winAmt, "Crash")
            crashFrame.statusText:SetText(GC_L("LOC_2563") .. winAmt .. GC_L("LOC_2564")..string.format("%.2f", currentMult).."x)|r")
            PlayCasinoSound(SOUNDKIT.RAID_WARNING)
            if currentMult >= 2.0 then AnnounceGameWin("Crash ("..string.format("%.2f", currentMult).."x)", winAmt) end
            
            crashFrame.actionBtn:Disable()
            crashFrame.actionBtn:SetText(GC_L("LOC_2570"))
            
            if ticker then ticker:Cancel() end
            ticker = C_Timer.NewTicker(0.05, function()
                currentMult = currentMult + (currentMult * 0.008)
                tickCount = tickCount + 1
                
                if currentMult >= crashPoint then
                    currentMult = crashPoint
                    ticker:Cancel()
                    crashFrame.rocket:Hide()
                    crashFrame.graphLine:SetColorTexture(1, 0, 0, 0.8)
                    crashFrame.multText:SetText(string.format("|cFFFF0000%.2fx|r", currentMult))
                    UpdateHistory(currentMult)
                    crashFrame.actionBtn:Enable()
                    crashFrame.actionBtn:SetText(GC_L("LOC_2572"))
                    crashFrame.actionBtn.bg:SetColorTexture(0.15, 0.15, 0.15, 0.9)
                    crashFrame.betInput:Enable()
                    PlaySound(856) 
                else
                    crashFrame.multText:SetText(string.format("%.2fx", currentMult))
                    local prog = math.min(1, tickCount / 200)
                    local curX, curY = 10 + (prog * 340), 10 + (prog * 180)
                    crashFrame.rocket:SetPoint("BOTTOMLEFT", crashFrame.graphBg, "BOTTOMLEFT", curX, curY)
                    crashFrame.graphLine:SetEndPoint("BOTTOMLEFT", crashFrame.graphBg, curX + 16, curY + 16)
                end
            end)
            
        else
            if ticker then ticker:Cancel() end
            crashFrame.rocket:Hide()
            crashFrame.graphLine:SetColorTexture(1, 0, 0, 0.8)
            crashFrame.statusText:SetText(GC_L("LOC_2577"))
            crashFrame.multText:SetText(string.format("|cFFFF0000%.2fx|r", currentMult))
            UpdateHistory(currentMult)
            crashFrame.actionBtn:Enable()
            crashFrame.actionBtn:SetText(GC_L("LOC_2579"))
            crashFrame.actionBtn.bg:SetColorTexture(0.15, 0.15, 0.15, 0.9)
            crashFrame.betInput:Enable()
            PlaySound(856)
        end
    end

    crashFrame.actionBtn:SetScript("OnClick", function()
        if isFlying then
            EndCrash(true)
        else
            currentBet = tonumber(crashFrame.betInput:GetText()) or 10
            if currentBet <= 0 then crashFrame.statusText:SetText(GC_L("LOC_2581")); return end
            if playChips < currentBet then crashFrame.statusText:SetText(GC_L("LOC_2582")); return end
            
            UpdatePlayChips(-currentBet)
            crashFrame.betInput:Disable()
            isFlying = true
            currentMult = 1.00
            tickCount = 0
            crashPoint = GetCrashPoint()
            
            crashFrame.rocket:Show()
            crashFrame.rocket:SetPoint("BOTTOMLEFT", crashFrame.graphBg, "BOTTOMLEFT", 10, 10)
            crashFrame.graphLine:SetColorTexture(1, 0.8, 0, 0.8) 
            crashFrame.graphLine:Show()
            crashFrame.graphLine:SetStartPoint("BOTTOMLEFT", crashFrame.graphBg, 10 + 16, 10 + 16)
            crashFrame.graphLine:SetEndPoint("BOTTOMLEFT", crashFrame.graphBg, 10 + 16, 10 + 16)

            crashFrame.statusText:SetText(GC_L("LOC_2587"))
            crashFrame.multText:SetText("1.00x")
            crashFrame.multText:SetTextColor(1, 1, 1)
            
            crashFrame.actionBtn:SetText(GC_L("LOC_2589"))
            crashFrame.actionBtn.bg:SetColorTexture(0.8, 0.5, 0.1, 0.9)
            
            if ticker then ticker:Cancel() end
            
            if crashPoint == 1.00 then
                EndCrash(false)
                return
            end

            PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")

            ticker = C_Timer.NewTicker(0.05, function()
                if not isFlying then return end
                
                currentMult = currentMult + (currentMult * 0.008)
                tickCount = tickCount + 1
                
                local prog = math.min(1, tickCount / 200)
                local curX, curY = 10 + (prog * 340), 10 + (prog * 180)
                crashFrame.rocket:SetPoint("BOTTOMLEFT", crashFrame.graphBg, "BOTTOMLEFT", curX, curY)
                crashFrame.graphLine:SetEndPoint("BOTTOMLEFT", crashFrame.graphBg, curX + 16, curY + 16)
                
                if currentMult >= crashPoint then
                    currentMult = crashPoint
                    EndCrash(false)
                else
                    crashFrame.multText:SetText(string.format("%.2fx", currentMult))
                    if currentMult < 2.0 then crashFrame.multText:SetTextColor(1, 1, 1)
                    elseif currentMult < 5.0 then crashFrame.multText:SetTextColor(1, 0.8, 0)
                    elseif currentMult < 10.0 then crashFrame.multText:SetTextColor(0, 1, 0)
                    else crashFrame.multText:SetTextColor(1, 0, 1) end
                end
            end)
        end
    end)
end

local banditFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); banditFrame:SetAllPoints(); banditFrame:Hide()
do
    banditFrame.title = banditFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    banditFrame.title:SetPoint("TOP", 0, -75); SetCustomFont(banditFrame.title, 22, "OUTLINE"); GC_RegisterLocalizedFontString(banditFrame.title, "LOC_GAME_LA_BANDITOS")

    banditFrame.statusText = banditFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    banditFrame.statusText:SetPoint("TOP", banditFrame.title, "BOTTOM", 0, -5); SetCustomFont(banditFrame.statusText, 14, "OUTLINE")
    banditFrame.statusText:SetText(GC_L("LOC_2606"))

    local ROWS, COLS = 5, 6
    local CELL_SIZE = 48
    local FIXED_BET = 50 
    local KAMERA_TEX = 7700743

    banditFrame.grid = CreateFrame("Frame", nil, banditFrame, "BackdropTemplate")
    banditFrame.grid:SetSize(COLS * (CELL_SIZE + 2) + 10, ROWS * (CELL_SIZE + 2) + 10)
    banditFrame.grid:SetPoint("CENTER", 0, 40)
    banditFrame.grid:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    banditFrame.grid:SetBackdropColor(0, 0, 0, 0.9); banditFrame.grid:SetBackdropBorderColor(0.4, 0.3, 0.1, 1)
	banditFrame.grid:SetClipsChildren(true)
    banditFrame.fsText = banditFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    banditFrame.fsText:SetPoint("BOTTOM", banditFrame.grid, "TOP", 0, 15)
    SetCustomFont(banditFrame.fsText, 18, "OUTLINE")
    banditFrame.fsText:SetTextColor(1, 0.8, 0)
    banditFrame.fsText:SetText("")

    local SYMBOLS = {
        {id=6, tex=646059, val=5.0, name="Bandit"},
        {id=5, tex=5221399, val=1.5, name=GC_L("LOC_2619")},
        {id=4, tex=134051, val=0.8, name=GC_L("LOC_2620")},
        {id=3, tex=132795, val=0.6, name=GC_L("LOC_2621")},
        {id=2, tex=133949, val=0.5, name=GC_L("LOC_2622")},
        {id=1, tex=133726, val=0.4, name=GC_L("LOC_2623")},
    }

    banditFrame.payoutTable = CreateFrame("Frame", nil, banditFrame, "BackdropTemplate")
    banditFrame.payoutTable:SetSize(140, 260)
    banditFrame.payoutTable:SetPoint("RIGHT", banditFrame, "CENTER", -180, 40)
    banditFrame.payoutTable:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    banditFrame.payoutTable:SetBackdropColor(0, 0, 0, 0.6); banditFrame.payoutTable:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)

    local tableTitle = banditFrame.payoutTable:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    tableTitle:SetPoint("TOP", 0, -10); tableTitle:SetText(GC_L("LOC_2633")); SetCustomFont(tableTitle, 11)

    for i, sym in ipairs(SYMBOLS) do
        local row = CreateFrame("Frame", nil, banditFrame.payoutTable)
        row:SetSize(120, 30); row:SetPoint("TOP", 0, -5 - (i*32))
        
        local icon = row:CreateTexture(nil, "ARTWORK")
        icon:SetSize(24, 24); icon:SetPoint("LEFT", 5, 0); icon:SetTexture(sym.tex)
        
        local txt = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        txt:SetPoint("LEFT", icon, "RIGHT", 5, 0)
        local minWin = math.floor(5 * sym.val * (FIXED_BET / 10))
        txt:SetText(sym.name .. ": " .. minWin .. "+")
        SetCustomFont(txt, 10)
    end

    local fsInfo = banditFrame.payoutTable:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    fsInfo:SetPoint("BOTTOM", banditFrame.payoutTable, "BOTTOM", 0, 10)
    SetCustomFont(fsInfo, 10, "OUTLINE")
    fsInfo:SetTextColor(1, 0.8, 0)
    GC_RegisterLocalizedFontString(fsInfo, "LOC_MANUAL_FREE_SPIN_TRIGGER")

    banditFrame.model = CreateFrame("PlayerModel", nil, banditFrame)
    banditFrame.model:SetSize(300, 340)
    banditFrame.model:SetPoint("LEFT", banditFrame, "CENTER", 100, -45)
    banditFrame.model:SetDisplayInfo(40092) 
    if banditFrame.model.SetAnimation then banditFrame.model:SetAnimation(0) end
    banditFrame.model:SetRotation(-0.5)

    local RAINBOW_TEX = 461790
    local COINS = {{tex=133788}, {tex=237282}, {tex=237281}}

    banditFrame.cells = {}
    for r = 1, ROWS do
        banditFrame.cells[r] = {}
        for c = 1, COLS do
            local f = CreateFrame("Frame", nil, banditFrame.grid, "BackdropTemplate")
            f:SetSize(CELL_SIZE, CELL_SIZE); f:SetPoint("TOPLEFT", (c-1)*(CELL_SIZE+2) + 5, -(r-1)*(CELL_SIZE+2) - 5)
            f.gold = f:CreateTexture(nil, "BACKGROUND"); f.gold:SetAllPoints(); f.gold:SetColorTexture(1, 0.7, 0, 0.4); f.gold:Hide()
            f.goldBorder = f:CreateTexture(nil, "OVERLAY"); f.goldBorder:SetAllPoints(); f.goldBorder:SetTexture("Interface\\Buttons\\CheckButtonGlow"); f.goldBorder:SetVertexColor(1, 0.8, 0); f.goldBorder:Hide()
            f.tex = f:CreateTexture(nil, "ARTWORK"); f.tex:SetAllPoints()

            f.dropAnim = f.tex:CreateAnimationGroup()
            
            f.instUp = f.dropAnim:CreateAnimation("Translation")
            f.instUp:SetOrder(1); f.instUp:SetDuration(0)       
            f.dropDown = f.dropAnim:CreateAnimation("Translation")
            f.dropDown:SetOrder(2); f.dropDown:SetSmoothing("IN")

            f.multText = f:CreateFontString(nil, "OVERLAY", "GameFontNormal"); f.multText:SetPoint("CENTER"); SetCustomFont(f.multText, 14, "OUTLINE"); f.multText:Hide()
            banditFrame.cells[r][c] = f
        end
    end

    banditFrame.flyingCoin = banditFrame.grid:CreateTexture(nil, "OVERLAY"); banditFrame.flyingCoin:SetSize(30, 30); banditFrame.flyingCoin:Hide()
    local isSpinning, currentWin = false, 0
    local isBanditFS = false
    local banditFSLeft = 0
    local banditBonusTotal = 0

    local function IsRainbowOnGrid()
        for r=1, ROWS do for c=1, COLS do if banditFrame.cells[r][c].symID == 10 then return r, c end end end
        return nil, nil
    end

    local function UpdateCellAlpha(r, c)
        local cell = banditFrame.cells[r][c]
        if cell.gold:IsShown() and cell.symID and cell.symID < 8 then cell.tex:SetAlpha(0.2) else cell.tex:SetAlpha(1) end
    end
	local function GetRandomBanditSymbol()
        local sym
        local rDrop = math.random(1, 1000)
        
        if rDrop > 967 then sym = {id=8, tex=KAMERA_TEX}
        elseif not IsRainbowOnGrid() and rDrop < 5 then sym = {id=10, tex=RAINBOW_TEX}
        else
            local symRand = math.random(1, 100)
            if symRand > 92 then sym = SYMBOLS[1]
            elseif symRand > 80 then sym = SYMBOLS[2]
            elseif symRand > 65 then sym = SYMBOLS[3]
            elseif symRand > 45 then sym = SYMBOLS[4]
            elseif symRand > 20 then sym = SYMBOLS[5]
            else sym = SYMBOLS[6] end
        end
        return sym
    end

    local function ApplyBanditGravity()
        local changed = false
        for c = 1, COLS do
            for r = ROWS, 2, -1 do
                if banditFrame.cells[r][c].tex:GetAlpha() == 0 then
                    local above = banditFrame.cells[r-1][c]
                    if above.symID then
                        banditFrame.cells[r][c].symID = above.symID
                        banditFrame.cells[r][c].tex:SetTexture(above.tex:GetTexture())
                        banditFrame.cells[r][c].tex:SetAlpha(1)
                        UpdateCellAlpha(r, c)
                        
                        if banditFrame.cells[r][c].dropAnim then
                            banditFrame.cells[r][c].instUp:SetOffset(0, CELL_SIZE + 2)
                            banditFrame.cells[r][c].dropDown:SetOffset(0, -(CELL_SIZE + 2))
                            banditFrame.cells[r][c].dropDown:SetDuration(0.15)
                            
                            banditFrame.cells[r][c].dropAnim:Stop()
                            banditFrame.cells[r][c].dropAnim:Play()
                        end
                        
                        above.symID = nil
                        above.tex:SetAlpha(0)
                        changed = true
                    end
                end
            end
            
            if not banditFrame.cells[1][c].symID or banditFrame.cells[1][c].tex:GetAlpha() == 0 then
                local sym = GetRandomBanditSymbol()
                banditFrame.cells[1][c].symID = sym.id
                banditFrame.cells[1][c].tex:SetTexture(sym.tex)
                banditFrame.cells[1][c].tex:SetAlpha(1)
                UpdateCellAlpha(1, c)
                
                if banditFrame.cells[1][c].dropAnim then
                    banditFrame.cells[1][c].instUp:SetOffset(0, CELL_SIZE + 2)
                    banditFrame.cells[1][c].dropDown:SetOffset(0, -(CELL_SIZE + 2))
                    banditFrame.cells[1][c].dropDown:SetDuration(0.15)
                    
                    banditFrame.cells[1][c].dropAnim:Stop()
                    banditFrame.cells[1][c].dropAnim:Play()
                end
                
                changed = true
            end
        end
        if changed then C_Timer.After(0.16, ApplyBanditGravity) else C_Timer.After(0.3, banditFrame.CheckWins) end
    end

    local function FlyCoin(fromR, fromC, toR, toC, coinTex, mult, callback)
        local startFrame = banditFrame.cells[fromR][fromC]; local endFrame = banditFrame.cells[toR][toC]
        banditFrame.flyingCoin:SetTexture(coinTex); banditFrame.flyingCoin:ClearAllPoints(); banditFrame.flyingCoin:SetPoint("CENTER", startFrame); banditFrame.flyingCoin:Show()
        local startX, startY = startFrame:GetCenter(); local endX, endY = endFrame:GetCenter(); local duration, elapsed = 0.2, 0
        local anim = CreateFrame("Frame")
        anim:SetScript("OnUpdate", function(self, dt)
            elapsed = elapsed + dt; local progress = elapsed / duration
            if progress >= 1 then self:SetScript("OnUpdate", nil); banditFrame.flyingCoin:Hide(); PlaySound(864, "Master"); callback()
            else local curX = startX + (endX - startX) * progress; local curY = startY + (endY - startY) * progress; banditFrame.flyingCoin:SetPoint("CENTER", UIParent, "BOTTOMLEFT", curX, curY) end
        end)
    end

    local function ActivateRainbow()
        local rbR, rbC = IsRainbowOnGrid()
        if not rbR then banditFrame.Finalize(); return end
        local targets = {}
        for r=1, ROWS do for c=1, COLS do if banditFrame.cells[r][c].gold:IsShown() then table.insert(targets, {r=r, c=c}) end end end
        if #targets == 0 then banditFrame.Finalize(); return end

        local function ProcessNext(idx)
            if not targets or idx > #targets then C_Timer.After(0.5, banditFrame.Finalize); return end

            local t = targets[idx]
            local r2 = math.random(1, 1000)
            local cData, mult

            if r2 > 999 then 
                cData = COINS[3]; mult = (math.random(1, 100) <= 90) and 50 or 100 
            elseif r2 > 970 then 
                cData = COINS[2]; local rS = math.random(1, 100)
                if rS <= 60 then mult = 10 elseif rS <= 85 then mult = 15 elseif rS <= 95 then mult = 20 else mult = 25 end
            else 
                cData = COINS[1]; local rB = math.random(1, 100)
                if rB <= 50 then mult = 0.5 elseif rB <= 75 then mult = 1 elseif rB <= 86 then mult = 2 elseif rB <= 92 then mult = 3 elseif rB <= 96 then mult = 4 elseif rB <= 99 then mult = 5 else mult = 10 end             
            end

            FlyCoin(rbR, rbC, t.r, t.c, cData.tex, mult, function()
                local val = math.floor(FIXED_BET * mult) 
                currentWin = currentWin + val; local cell = banditFrame.cells[t.r][t.c]
                cell.tex:SetTexture(cData.tex); cell.tex:SetAlpha(1); cell.multText:SetText(mult .. "x"); cell.multText:Show()
                if not isBanditFS then
                    cell.gold:Hide(); cell.goldBorder:Hide()
                end
                
                local extraStr = isBanditFS and (GC_L("LOC_2676") .. (banditBonusTotal + currentWin) .. GC_L("LOC_2677")) or ""
                banditFrame.statusText:SetText(GC_L("LOC_2679") .. currentWin .. extraStr .. "|r"); 
                ProcessNext(idx + 1)
            end)
        end
        ProcessNext(1)
    end

    local function FindCluster(r, c, id, visited)
        if r < 1 or r > ROWS or c < 1 or c > COLS or visited[r][c] or banditFrame.cells[r][c].symID ~= id or id >= 8 then return 0, {} end
        visited[r][c] = true; local size, cluster = 1, {{r, c}}; local neighbors = {{r-1, c}, {r+1, c}, {r, c-1}, {r, c+1}}
        for _, n in ipairs(neighbors) do local s, cl = FindCluster(n[1], n[2], id, visited); size = size + s; for _, coord in ipairs(cl) do table.insert(cluster, coord) end end
        return size, cluster
    end

    function banditFrame.CheckWins()
        local visited = {}; for r=1, ROWS do visited[r] = {} end
        local wonThisTumble = false; local hasRainbow = IsRainbowOnGrid() ~= nil
        local cameraCount = 0

        for r=1, ROWS do for c=1, COLS do
            local cId = banditFrame.cells[r][c].symID
            if cId == 8 then cameraCount = cameraCount + 1 end

            if not visited[r][c] and cId and cId < 8 then
                local size, cluster = FindCluster(r, c, cId, visited)
                if size >= 5 then
                    wonThisTumble = true
                    local baseVal = 0
                    for _, s in ipairs(SYMBOLS) do if s.id == cId then baseVal = s.val break end end
                    
                    currentWin = currentWin + math.floor(size * baseVal * (FIXED_BET / 10)) 
                    for _, coord in ipairs(cluster) do 
                        local cell = banditFrame.cells[coord[1]][coord[2]]
                        cell.symID = nil; cell.tex:SetAlpha(0); cell.gold:Show(); cell.goldBorder:Show() 
                    end
                end
            end
        end end

        if wonThisTumble then 
            PlaySound(1210, "Master")
            local extraStr = isBanditFS and (GC_L("LOC_2682") .. (banditBonusTotal + currentWin) .. GC_L("LOC_2683")) or ""
            banditFrame.statusText:SetText(GC_L("LOC_2685") .. currentWin .. extraStr .. "|r")
            C_Timer.After(0.4, ApplyBanditGravity)
        else 
            if cameraCount >= 4 and not isBanditFS then
                isBanditFS = true
                banditFSLeft = 10
                banditFrame.fsText:SetText(GC_L("LOC_2687"))
                PlaySound(8440)
                
                if hasRainbow then
                    C_Timer.After(2, ActivateRainbow)
                else
                    C_Timer.After(2, banditFrame.Finalize)
                end
            elseif hasRainbow then 
                ActivateRainbow() 
            else 
                banditFrame.Finalize() 
            end 
        end
    end

    function banditFrame.Finalize()
        if isBanditFS then
            banditBonusTotal = banditBonusTotal + currentWin
            currentWin = 0
            if banditFSLeft > 0 then
                C_Timer.After(1, banditFrame.DoSpin)
                return
            else
                isBanditFS = false
                if banditBonusTotal > 0 then
                    UpdatePlayChips(banditBonusTotal); AddChipTransaction(CleanName(UnitName("player")), banditBonusTotal, "La Banditos (FS)"); AnnounceGameWin(GC_L("LOC_2690"), banditBonusTotal)
                    banditFrame.statusText:SetText(GC_L("LOC_2691") .. banditBonusTotal .. GC_L("LOC_2692"))
                else
                    banditFrame.statusText:SetText(GC_L("LOC_2693"))
                end
                banditFrame.fsText:SetText("")
            end
        else
            if currentWin > 0 then 
                UpdatePlayChips(currentWin); AddChipTransaction(CleanName(UnitName("player")), currentWin, "La Banditos"); AnnounceGameWin("Le Bandit", currentWin)
            else 
                AddChipTransaction(CleanName(UnitName("player")), -FIXED_BET, "La Banditos"); banditFrame.statusText:SetText(GC_L("LOC_2700")) 
            end
        end
        isSpinning = false; banditFrame.spinBtn:Enable()
    end

    function banditFrame.DoSpin()
        isSpinning = true; banditFrame.spinBtn:Disable(); currentWin = 0
        if isBanditFS then
            banditFSLeft = banditFSLeft - 1
            banditFrame.fsText:SetText(GC_L("LOC_2701") .. banditFSLeft .. GC_L("LOC_2702") .. banditBonusTotal .. GC_L("LOC_2703"))
            banditFrame.statusText:SetText(GC_L("LOC_2704"))
        else
            if playChips < FIXED_BET then banditFrame.statusText:SetText(GC_L("LOC_2705")); isSpinning = false; banditFrame.spinBtn:Enable(); return end
            UpdatePlayChips(-FIXED_BET); banditFrame.statusText:SetText(GC_L("LOC_2706")); banditBonusTotal = 0; banditFrame.fsText:SetText("")
        end

        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")

        for r = 1, ROWS do
            for c = 1, COLS do
                banditFrame.cells[r][c].tex:SetAlpha(0)
                banditFrame.cells[r][c].symID = nil

                if not isBanditFS then
                    banditFrame.cells[r][c].gold:Hide()
                    banditFrame.cells[r][c].goldBorder:Hide()
                end
                
                banditFrame.cells[r][c].multText:Hide()
            end
        end

        for c = 1, COLS do
            C_Timer.After((c - 1) * 0.1, function()
                for r = ROWS, 1, -1 do 
                    C_Timer.After((ROWS - r) * 0.08, function()
                        local cell = banditFrame.cells[r][c]
                        local sym = GetRandomBanditSymbol()
                        
                        cell.symID = sym.id
                        cell.tex:SetTexture(sym.tex)
                        cell.tex:SetAlpha(1)
                        UpdateCellAlpha(r, c)
                        
                        if cell.dropAnim then
                            local dropDistance = r * (CELL_SIZE + 2)
                            cell.instUp:SetOffset(0, dropDistance)
                            cell.dropDown:SetOffset(0, -dropDistance)

                            cell.dropDown:SetDuration(r * 0.06) 
                            
                            cell.dropAnim:Stop()
                            cell.dropAnim:Play()
                        end
                    end)
                end
                
                if c == COLS then
                    C_Timer.After(0.7, banditFrame.CheckWins)
                end
            end)
        end
    end

    banditFrame.spinBtn = CreateLocalizedButton(banditFrame, "LOC_2709", 150, 40)
    banditFrame.spinBtn:SetPoint("BOTTOM", 0, 42)
    banditFrame.spinBtn:SetScript("OnClick", function() if not isSpinning then banditFrame.DoSpin() end end)
end

local bookFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay)
bookFrame:SetAllPoints()
bookFrame:Hide()

do
    bookFrame.title = bookFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    bookFrame.title:SetPoint("TOP", 0, -60)
    SetCustomFont(bookFrame.title, 22, "OUTLINE")
    GC_RegisterLocalizedFontString(bookFrame.title, "LOC_GAME_BOOK_OF_AZEROTH")

    bookFrame.statusText = bookFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    bookFrame.statusText:SetPoint("TOP", bookFrame.title, "BOTTOM", 0, -5)
    SetCustomFont(bookFrame.statusText, 14, "OUTLINE")
    bookFrame.statusText:SetText(GC_L("LOC_2723"))

    local ROWS, COLS = 3, 5
    local CELL_W, CELL_H = 65, 65
    local FIXED_BET = 50 

    bookFrame.grid = CreateFrame("Frame", nil, bookFrame, "BackdropTemplate")
    bookFrame.grid:SetSize(COLS * (CELL_W + 4) + 10, ROWS * (CELL_H + 4) + 10)
    bookFrame.grid:SetPoint("CENTER", 0, 40)
    bookFrame.grid:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 2})
    bookFrame.grid:SetBackdropColor(0.05, 0.02, 0.05, 0.95)
    bookFrame.grid:SetBackdropBorderColor(0.8, 0.6, 0.1, 1)
    bookFrame.grid:SetClipsChildren(true)

    bookFrame.fsText = bookFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    bookFrame.fsText:SetPoint("BOTTOM", bookFrame.grid, "TOP", 0, 10)
    SetCustomFont(bookFrame.fsText, 18, "OUTLINE")
    bookFrame.fsText:SetTextColor(1, 0.8, 0)
    bookFrame.fsText:SetText("")

    bookFrame.expandingIcon = bookFrame:CreateTexture(nil, "OVERLAY")
    bookFrame.expandingIcon:SetSize(40, 40)
    bookFrame.expandingIcon:SetPoint("BOTTOMRIGHT", bookFrame.grid, "TOPLEFT", -15, 0)
    bookFrame.expandingIcon:Hide()
    bookFrame.expandingText = bookFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
    bookFrame.expandingText:SetPoint("CENTER", bookFrame.expandingIcon, "CENTER")
    SetCustomFont(bookFrame.expandingText, 24, "OUTLINE")
    bookFrame.expandingText:Hide()
    
    local expandingBorder = bookFrame:CreateTexture(nil, "OVERLAY")
    expandingBorder:SetAllPoints(bookFrame.expandingIcon)
    expandingBorder:SetTexture("Interface\\Buttons\\CheckButtonGlow")
    expandingBorder:SetVertexColor(1, 0.8, 0)
    expandingBorder:Hide()
    bookFrame.expandingBorder = expandingBorder

    local SYMBOLS = {
        [1] = {id=1, tex="Interface\\Icons\\INV_Misc_Book_09", isHigh=true, isBook=true, pays={0, 0, 2, 20, 200}},
        [2] = {id=2, tex="Interface\\Icons\\quest_khadgar", isHigh=true, pays={0, 1, 10, 100, 500}},
        [3] = {id=3, tex="Interface\\Icons\\inv_armor_phoenix_d_01_helm", isHigh=true, pays={0, 0.5, 4, 40, 200}},
        [4] = {id=4, tex="Interface\\Icons\\inv_misc_pheonixpet_01", isHigh=true, pays={0, 0.5, 3, 10, 75}},
        [5] = {id=5, tex="Interface\\Icons\\inv_misc_ahnqirajtrinket_01", isHigh=true, pays={0, 0.5, 3, 10, 75}},
        [6] = {id=6, tex=nil, text="A", isHigh=false, pays={0, 0, 0.5, 4, 15}},
        [7] = {id=7, tex=nil, text="K", isHigh=false, pays={0, 0, 0.5, 4, 15}},
        [8] = {id=8, tex=nil, text="Q", isHigh=false, pays={0, 0, 0.5, 2.5, 10}},
        [9] = {id=9, tex=nil, text="J", isHigh=false, pays={0, 0, 0.5, 2.5, 10}},
        [10]= {id=10, tex=nil, text="10", isHigh=false, pays={0, 0, 0.5, 2.5, 10}}
    }

    local PAYLINES = {
        {2,2,2,2,2}, {1,1,1,1,1}, {3,3,3,3,3}, {1,2,3,2,1}, {3,2,1,2,3},
        {2,1,1,1,2}, {2,3,3,3,2}, {1,1,2,3,3}, {3,3,2,1,1}, {2,3,2,1,2}
    }

    bookFrame.cells = {}
    for r = 1, ROWS do
        bookFrame.cells[r] = {}
        for c = 1, COLS do
            local f = CreateFrame("Frame", nil, bookFrame.grid, "BackdropTemplate")
            f:SetSize(CELL_W, CELL_H)
            f:SetPoint("TOPLEFT", (c-1)*(CELL_W+4) + 7, -(r-1)*(CELL_H+4) - 7)
            
            f.bg = f:CreateTexture(nil, "BACKGROUND")
            f.bg:SetAllPoints()
            f.bg:SetColorTexture(0.1, 0.1, 0.1, 1)

            f.expandBg = f:CreateTexture(nil, "BORDER")
            f.expandBg:SetAllPoints()
            f.expandBg:SetColorTexture(0.8, 0.6, 0.1, 0.8)
            f.expandBg:Hide()

            f.tex = f:CreateTexture(nil, "ARTWORK")
            f.tex:SetAllPoints()
            f.tex:SetTexCoord(0.08, 0.92, 0.08, 0.92)

            f.fsText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
            f.fsText:SetPoint("CENTER")
            SetCustomFont(f.fsText, 32, "OUTLINE")
            f.fsText:Hide()

            f.glow = f:CreateTexture(nil, "OVERLAY")
            f.glow:SetAllPoints()
            f.glow:SetTexture("Interface\\Buttons\\CheckButtonGlow")
            f.glow:SetVertexColor(1, 0.8, 0)
            f.glow:Hide()

            bookFrame.cells[r][c] = f
        end
    end

    local isSpinning, currentWin = false, 0
    local isFreeSpins = false
    local freeSpinsLeft = 0
    local bonusTotal = 0
    local expandSymID = 0

    bookFrame.paylines = {}

    bookFrame.lineLayer = CreateFrame("Frame", nil, bookFrame.grid)
    bookFrame.lineLayer:SetAllPoints()
    bookFrame.lineLayer:SetFrameLevel(bookFrame.grid:GetFrameLevel() + 15)

    local function ClearPaylines()
        for _, line in ipairs(bookFrame.paylines) do
            line:Hide()
        end
    end

    local function DrawPayline(path)
        local colors = { {1, 0.8, 0}, {0, 1, 0}, {0, 0.8, 1}, {1, 0, 1}, {1, 0.2, 0.2} }
        local c = colors[math.random(1, #colors)]

        for i = 1, #path - 1 do
            local startCell = bookFrame.cells[path[i][1]][path[i][2]]
            local endCell = bookFrame.cells[path[i+1][1]][path[i+1][2]]

            local line = bookFrame.lineLayer:CreateLine(nil, "OVERLAY", nil, 7)
            line:SetThickness(8)
            line:SetColorTexture(c[1], c[2], c[3], 0.9)
            line:SetStartPoint("CENTER", startCell)
            line:SetEndPoint("CENTER", endCell)
            line:Show()
            
            table.insert(bookFrame.paylines, line)
        end
    end

    local function GetRandomBookSymbol()
        local r = math.random(1, 1000)
        if r > 955 then return SYMBOLS[1]
        elseif r > 925 then return SYMBOLS[2]
        elseif r > 910 then return SYMBOLS[3]
        elseif r > 880 then return SYMBOLS[4]
        elseif r > 830 then return SYMBOLS[5]
        elseif r > 680 then return SYMBOLS[6]
        elseif r > 530 then return SYMBOLS[7]
        elseif r > 350 then return SYMBOLS[8]
        elseif r > 170 then return SYMBOLS[9]
        else return SYMBOLS[10] end
    end

    local function ApplySymbolVisual(r, c, sym)
        local cell = bookFrame.cells[r][c]
        cell.symID = sym.id
        cell.glow:Hide()
        cell.expandBg:Hide()
        if sym.tex then
            cell.tex:SetTexture(sym.tex)
            cell.tex:Show()
            cell.fsText:Hide()
        else
            cell.tex:Hide()
            cell.fsText:SetText(sym.text)
            if sym.id == 6 then cell.fsText:SetTextColor(1, 0, 0)
            elseif sym.id == 7 then cell.fsText:SetTextColor(0, 0.8, 1)
            elseif sym.id == 8 then cell.fsText:SetTextColor(1, 0.5, 0)
            elseif sym.id == 9 then cell.fsText:SetTextColor(0, 1, 0)
            else cell.fsText:SetTextColor(1, 1, 1) end
            cell.fsText:Show()
        end
    end

    function bookFrame.CheckWins()
        local spinTotal = 0
        local booksFound = 0
        local bookCoords = {}

        local MAX_WIN_CAP = 75000 
        local hitMaxWin = false
        for lineIdx, linePath in ipairs(PAYLINES) do
            local firstSym = nil
            local matchCount = 0
            local winPath = {}

            for c = 1, COLS do
                local r = linePath[c]
                local cSym = bookFrame.cells[r][c].symID

                if cSym == 1 then
                    matchCount = matchCount + 1
                    table.insert(winPath, {r, c})
                else
                    if not firstSym then
                        firstSym = cSym
                        matchCount = matchCount + 1
                        table.insert(winPath, {r, c})
                    elseif cSym == firstSym then
                        matchCount = matchCount + 1
                        table.insert(winPath, {r, c})
                    else
                        break
                    end
                end
            end

            local evalSym = firstSym or 2 
            local symData = SYMBOLS[evalSym]

            if symData and matchCount > 0 and symData.pays[matchCount] > 0 then
                local lineWin = FIXED_BET * symData.pays[matchCount]
                spinTotal = spinTotal + lineWin
                
                DrawPayline(winPath)

                for _, coord in ipairs(winPath) do
                    bookFrame.cells[coord[1]][coord[2]].glow:Show()
                end
            end
        end

        for r = 1, ROWS do
            for c = 1, COLS do
                if bookFrame.cells[r][c].symID == 1 then
                    booksFound = booksFound + 1
                    table.insert(bookCoords, {r, c})
                end
            end
        end

        if booksFound >= 3 then
            spinTotal = spinTotal + (FIXED_BET * SYMBOLS[1].pays[booksFound])
            for _, coord in ipairs(bookCoords) do
                bookFrame.cells[coord[1]][coord[2]].glow:SetVertexColor(1, 0, 1)
                bookFrame.cells[coord[1]][coord[2]].glow:Show()
            end
        end

        if bonusTotal + currentWin + spinTotal >= MAX_WIN_CAP then
            spinTotal = MAX_WIN_CAP - (bonusTotal + currentWin)
            hitMaxWin = true
            freeSpinsLeft = 0
        end

        currentWin = currentWin + spinTotal
        if spinTotal > 0 then
            if hitMaxWin then
                bookFrame.statusText:SetText(GC_L("LOC_2771"))
                PlaySound(8440, "Master")
            else
                PlaySound(1210, "Master")
                local extraStr = isFreeSpins and (GC_L("LOC_2774") .. (bonusTotal + currentWin) .. GC_L("LOC_2775")) or ""
                bookFrame.statusText:SetText(GC_L("LOC_2777") .. currentWin .. extraStr .. "|r")
            end
        end

        local function ProcessExpansion()
            local expandWin = 0
            local willExpand = false
            local eSymData = nil
            local targetReels = {}
            local reelsWithSym = 0

            if isFreeSpins and expandSymID > 1 and not hitMaxWin then 
                eSymData = SYMBOLS[expandSymID]

                for c = 1, COLS do
                    for r = 1, ROWS do
                        if bookFrame.cells[r][c].symID == expandSymID then
                            reelsWithSym = reelsWithSym + 1
                            table.insert(targetReels, c)
                            break
                        end
                    end
                end

                local minNeeded = eSymData.isHigh and 2 or 3
                if reelsWithSym >= minNeeded then
                    willExpand = true
                end
            end

            if willExpand then
                ClearPaylines()
                for r=1, ROWS do for c=1, COLS do 
                    bookFrame.cells[r][c].glow:Hide()
                    bookFrame.cells[r][c].glow:SetVertexColor(1, 0.8, 0)
                end end

                PlaySound(1186, "Master") 
                local multiplier = eSymData.pays[reelsWithSym]
                expandWin = FIXED_BET * multiplier * 10 

                if bonusTotal + currentWin + expandWin >= MAX_WIN_CAP then
                    expandWin = MAX_WIN_CAP - (bonusTotal + currentWin)
                    hitMaxWin = true
                    freeSpinsLeft = 0
                end

                for _, c in ipairs(targetReels) do
                    for r = 1, ROWS do
                        bookFrame.cells[r][c].expandBg:Show()
                        ApplySymbolVisual(r, c, eSymData)
                        bookFrame.cells[r][c].glow:Show()
                    end
                end
                
                currentWin = currentWin + expandWin
                
                if hitMaxWin then
                    bookFrame.statusText:SetText(GC_L("LOC_2780"))
                    PlaySound(8440, "Master")
                else
                    local extraStr = GC_L("LOC_2782") .. (bonusTotal + currentWin) .. GC_L("LOC_2783")
                    bookFrame.statusText:SetText(GC_L("LOC_2784") .. currentWin .. extraStr .. "|r")
                    PlaySound(1210, "Master")
                end
                
                C_Timer.After(1.5, function() bookFrame.Finalize(hitMaxWin and 0 or booksFound) end)
            else
                if spinTotal > 0 and not isFreeSpins then
                    C_Timer.After(1.5, function() bookFrame.Finalize(hitMaxWin and 0 or booksFound) end)
                elseif spinTotal > 0 and isFreeSpins then
                    bookFrame.Finalize(hitMaxWin and 0 or booksFound)
                else
                    C_Timer.After(0.3, function() bookFrame.Finalize(hitMaxWin and 0 or booksFound) end)
                end
            end
        end

        if spinTotal > 0 and isFreeSpins then
            C_Timer.After(1.5, ProcessExpansion)
        else
            ProcessExpansion()
        end
    end

    function bookFrame.Finalize(books)
        if books >= 3 then
            if not isFreeSpins then
                isFreeSpins = true
                freeSpinsLeft = 10
                bonusTotal = currentWin
                currentWin = 0
                
                expandSymID = math.random(2, 10)
                local eSym = SYMBOLS[expandSymID]
                
                if eSym.tex then
                    bookFrame.expandingIcon:SetTexture(eSym.tex)
                    bookFrame.expandingIcon:SetVertexColor(1, 1, 1, 1)
                    bookFrame.expandingIcon:Show()
                    bookFrame.expandingText:Hide()
                else
                    bookFrame.expandingIcon:SetTexture("Interface\\Buttons\\WHITE8X8")
                    bookFrame.expandingIcon:SetVertexColor(0.1, 0.1, 0.1, 0.9)
                    bookFrame.expandingIcon:Show()
                    
                    bookFrame.expandingText:SetText(eSym.text)
                    if eSym.id == 6 then bookFrame.expandingText:SetTextColor(1, 0, 0)
                    elseif eSym.id == 7 then bookFrame.expandingText:SetTextColor(0, 0.8, 1)
                    elseif eSym.id == 8 then bookFrame.expandingText:SetTextColor(1, 0.5, 0)
                    elseif eSym.id == 9 then bookFrame.expandingText:SetTextColor(0, 1, 0)
                    else bookFrame.expandingText:SetTextColor(1, 1, 1) end
                    bookFrame.expandingText:Show()
                end
                bookFrame.expandingIcon:Show()
                bookFrame.expandingBorder:Show()
                
                bookFrame.fsText:SetText(GC_L("LOC_2788"))
                PlaySound(8440)
                
                C_Timer.After(3, bookFrame.DoSpin)
                return
            else
                freeSpinsLeft = freeSpinsLeft + 10
                bookFrame.fsText:SetText(GC_L("LOC_2789"))
                PlaySound(8440)
            end
        end

        if isFreeSpins then
            bonusTotal = bonusTotal + currentWin
            currentWin = 0
            if freeSpinsLeft > 0 then
                C_Timer.After(1, bookFrame.DoSpin)
            else
                isFreeSpins = false
                bookFrame.expandingIcon:Hide()
                bookFrame.expandingText:Hide()
                bookFrame.expandingBorder:Hide()
                if bonusTotal > 0 then
                    UpdatePlayChips(bonusTotal)
                    AddChipTransaction(CleanName(UnitName("player")), bonusTotal, "Book of Azeroth (FS)")
                    AnnounceGameWin(GC_L("LOC_2792"), bonusTotal)
                    bookFrame.statusText:SetText(GC_L("LOC_2793") .. bonusTotal .. GC_L("LOC_2794"))
                else
                    bookFrame.statusText:SetText(GC_L("LOC_2795"))
                end
                bookFrame.fsText:SetText("")
                isSpinning = false
                bookFrame.spinBtn:Enable()
            end
        else
            if currentWin > 0 then 
                UpdatePlayChips(currentWin)
                AddChipTransaction(CleanName(UnitName("player")), currentWin, "Book of Azeroth")
                AnnounceGameWin("Book of Azeroth", currentWin)
            else 
                AddChipTransaction(CleanName(UnitName("player")), -FIXED_BET, "Book of Azeroth")
                bookFrame.statusText:SetText(GC_L("LOC_2802")) 
            end
            isSpinning = false
            bookFrame.spinBtn:Enable()
        end
    end

    function bookFrame.DoSpin()
        isSpinning = true
        bookFrame.spinBtn:Disable()
        currentWin = 0
        
        ClearPaylines()

        if isFreeSpins then
            freeSpinsLeft = freeSpinsLeft - 1
            bookFrame.fsText:SetText(GC_L("LOC_MANUAL_FREE_SPINS_PREFIX") .. freeSpinsLeft .. GC_L("LOC_2804") .. bonusTotal .. GC_L("LOC_2805"))
            bookFrame.statusText:SetText(GC_L("LOC_2806"))
        else
            if playChips < FIXED_BET then 
                bookFrame.statusText:SetText(GC_L("LOC_2807"))
                isSpinning = false
                bookFrame.spinBtn:Enable()
                return 
            end
            UpdatePlayChips(-FIXED_BET)
            bookFrame.statusText:SetText(GC_L("LOC_2808"))
            bonusTotal = 0
            bookFrame.fsText:SetText("")
        end

        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")

        local finalBoard = {}
        for r = 1, ROWS do
            finalBoard[r] = {}
            for c = 1, COLS do
                finalBoard[r][c] = GetRandomBookSymbol()
                bookFrame.cells[r][c].glow:Hide()
                bookFrame.cells[r][c].expandBg:Hide()
            end
        end

        for c = 1, COLS do
            local ticksCount = 8 + (c * 6) 
            local ticker
            ticker = C_Timer.NewTicker(0.05, function()
                ticksCount = ticksCount - 1
                
                if ticksCount > 0 then
                    for r = 1, ROWS do
                        ApplySymbolVisual(r, c, GetRandomBookSymbol())
                    end
                else
                    ticker:Cancel()
                    PlaySound(856)
                    
                    for r = 1, ROWS do
                        ApplySymbolVisual(r, c, finalBoard[r][c])
                        
                        local cell = bookFrame.cells[r][c]
                        cell.bg:SetColorTexture(0.3, 0.3, 0.3, 1) 
                        C_Timer.After(0.15, function() cell.bg:SetColorTexture(0.1, 0.1, 0.1, 1) end)
                    end
                    
                    if c == COLS then
                        C_Timer.After(0.3, bookFrame.CheckWins)
                    end
                end
            end)
        end
    end

    bookFrame.spinBtn = CreateLocalizedButton(bookFrame, "LOC_2811", 150, 40)
    bookFrame.spinBtn:SetPoint("BOTTOM", 0, 42)
    bookFrame.spinBtn.bg:SetColorTexture(0.6, 0.4, 0.1, 0.9)
    bookFrame.spinBtn:SetScript("OnClick", function() if not isSpinning then bookFrame.DoSpin() end end)

    bookFrame.infoBtn = CreateLocalizedButton(bookFrame, "LOC_3373", 80, 40)
    bookFrame.infoBtn:SetPoint("RIGHT", bookFrame.spinBtn, "LEFT", -15, 0)
    bookFrame.infoBtn.bg:SetColorTexture(0.2, 0.4, 0.8, 0.9)
    bookFrame.infoBtn:SetScript("OnClick", function()
        if bookFrame.paytablePanel:IsVisible() then
            bookFrame.paytablePanel:Hide()
            PlaySound(840)
        else
            bookFrame.paytablePanel:Show()
            PlaySound(839)
        end
    end)

    bookFrame.paytablePanel = CreateFrame("Frame", nil, bookFrame, "BackdropTemplate")
    bookFrame.paytablePanel:SetSize(540, 420)
    bookFrame.paytablePanel:SetPoint("CENTER", bookFrame.grid, "CENTER", 0, 0)
    bookFrame.paytablePanel:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 2})
    bookFrame.paytablePanel:SetBackdropColor(0.1, 0.05, 0.1, 0.98)
    bookFrame.paytablePanel:SetBackdropBorderColor(0.8, 0.6, 0.1, 1)
    bookFrame.paytablePanel:Hide()
    bookFrame.paytablePanel:SetFrameLevel(bookFrame.grid:GetFrameLevel() + 20) 
    local ptTitle = bookFrame.paytablePanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    ptTitle:SetPoint("TOP", 0, -15)
    SetCustomFont(ptTitle, 18, "OUTLINE")
    ptTitle:SetTextColor(1, 0.8, 0)
    ptTitle:SetText(GC_L("LOC_2828"))
    
    local ptSubTitle = bookFrame.paytablePanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    ptSubTitle:SetPoint("TOP", ptTitle, "BOTTOM", 0, -5)
    SetCustomFont(ptSubTitle, 12, "OUTLINE")
    ptSubTitle:SetText(GC_L("LOC_2834"))
    local closePtBtn = CreateFrame("Button", nil, bookFrame.paytablePanel, "UIPanelCloseButton")
    closePtBtn:SetPoint("TOPRIGHT", -5, -5)
    closePtBtn:SetScript("OnClick", function() 
        bookFrame.paytablePanel:Hide() 
        PlaySound(840) 
    end)

    local leftX, rightX = 30, 280
    local startY = -80
    local rowStep = 60

    for i = 1, 10 do
        local sym = SYMBOLS[i]
        local isRightCol = i > 5
        local xOff = isRightCol and rightX or leftX
        local yOff = startY - ((i - 1) % 5) * rowStep
        local iconContainer = CreateFrame("Frame", nil, bookFrame.paytablePanel, "BackdropTemplate")
        iconContainer:SetSize(40, 40)
        iconContainer:SetPoint("TOPLEFT", xOff, yOff)
        iconContainer:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
        iconContainer:SetBackdropColor(0,0,0,1)
        iconContainer:SetBackdropBorderColor(0.5,0.5,0.5,1)

        if sym.tex then
            local tex = iconContainer:CreateTexture(nil, "ARTWORK")
            tex:SetAllPoints()
            tex:SetTexCoord(0.08, 0.92, 0.08, 0.92)
            tex:SetTexture(sym.tex)
        else
            local fs = iconContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
            fs:SetPoint("CENTER")
            SetCustomFont(fs, 22, "OUTLINE")
            fs:SetText(sym.text)
            if sym.id == 6 then fs:SetTextColor(1, 0, 0)
            elseif sym.id == 7 then fs:SetTextColor(0, 0.8, 1)
            elseif sym.id == 8 then fs:SetTextColor(1, 0.5, 0)
            elseif sym.id == 9 then fs:SetTextColor(0, 1, 0)
            else fs:SetTextColor(1, 1, 1) end
        end

        local textFrame = bookFrame.paytablePanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        textFrame:SetPoint("LEFT", iconContainer, "RIGHT", 15, 0)
        textFrame:SetJustifyH("LEFT")
        SetCustomFont(textFrame, 12, "OUTLINE")

        local lines = {}
        for matchCount = 5, 2, -1 do
            if sym.pays[matchCount] and sym.pays[matchCount] > 0 then
                local winAmount = sym.pays[matchCount] * FIXED_BET 
                table.insert(lines, "|cFFFFD100" .. matchCount .. "x:|r " .. winAmount)
            end
        end
        
        local payText = ""
        if #lines == 4 then
            payText = lines[1] .. "    " .. lines[2] .. "\n" .. lines[3] .. "    " .. lines[4]
        elseif #lines == 3 then
            payText = lines[1] .. "    " .. lines[2] .. "\n" .. lines[3]
        else
            payText = table.concat(lines, "    ")
        end
        
        textFrame:SetText(payText)
    end

    bookFrame.linesBtn = CreateLocalizedButton(bookFrame, "LOC_2864", 80, 40)
    bookFrame.linesBtn:SetPoint("LEFT", bookFrame.spinBtn, "RIGHT", 15, 0)
    bookFrame.linesBtn.bg:SetColorTexture(0.8, 0.2, 0.2, 0.9)
    bookFrame.linesBtn:SetScript("OnClick", function()
        if bookFrame.linesPanel:IsVisible() then
            bookFrame.linesPanel:Hide()
            PlaySound(840)
        else
            bookFrame.linesPanel:Show()
            bookFrame.paytablePanel:Hide()
            PlaySound(839)
        end
    end)

    bookFrame.infoBtn:SetScript("OnClick", function()
        if bookFrame.paytablePanel:IsVisible() then
            bookFrame.paytablePanel:Hide()
            PlaySound(840)
        else
            bookFrame.paytablePanel:Show()
            if bookFrame.linesPanel then bookFrame.linesPanel:Hide() end
            PlaySound(839)
        end
    end)

    bookFrame.linesPanel = CreateFrame("Frame", nil, bookFrame, "BackdropTemplate")
    bookFrame.linesPanel:SetSize(480, 240)
    bookFrame.linesPanel:SetPoint("CENTER", bookFrame.grid, "CENTER", 0, 0)
    bookFrame.linesPanel:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 2})
    bookFrame.linesPanel:SetBackdropColor(0.1, 0.05, 0.1, 0.98)
    bookFrame.linesPanel:SetBackdropBorderColor(0.8, 0.2, 0.2, 1)
    bookFrame.linesPanel:Hide()
    bookFrame.linesPanel:SetFrameLevel(bookFrame.grid:GetFrameLevel() + 20)

    local lpTitle = bookFrame.linesPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    lpTitle:SetPoint("TOP", 0, -15)
    SetCustomFont(lpTitle, 18, "OUTLINE")
    lpTitle:SetTextColor(1, 0.8, 0)
    lpTitle:SetText(GC_L("LOC_2879"))
    local closeLpBtn = CreateFrame("Button", nil, bookFrame.linesPanel, "UIPanelCloseButton")
    closeLpBtn:SetPoint("TOPRIGHT", -5, -5)
    closeLpBtn:SetScript("OnClick", function() bookFrame.linesPanel:Hide(); PlaySound(840) end)

    local startX = 40
    local startY = -60
    local stepX = 85
    local stepY = 90

    for i = 1, 10 do
        local col = (i - 1) % 5
        local row = math.floor((i - 1) / 5)
        
        local xOff = startX + (col * stepX)
        local yOff = startY - (row * stepY)
        
        local miniGrid = CreateFrame("Frame", nil, bookFrame.linesPanel)
        miniGrid:SetSize(68, 44)
        miniGrid:SetPoint("TOPLEFT", xOff, yOff)
        
        local numText = miniGrid:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        numText:SetPoint("BOTTOM", miniGrid, "TOP", 0, 2)
        SetCustomFont(numText, 12, "OUTLINE")
        numText:SetText(i .. ".")
        numText:SetTextColor(1, 0.8, 0)
        
        local boxW, boxH = 12, 12
        local gap = 2
        for r = 1, 3 do
            for c = 1, 5 do
                local box = miniGrid:CreateTexture(nil, "ARTWORK")
                box:SetSize(boxW, boxH)
                box:SetPoint("TOPLEFT", (c-1)*(boxW+gap), -(r-1)*(boxH+gap))
                if PAYLINES[i][c] == r then
                    box:SetColorTexture(1, 0.2, 0.2, 1)
                else
                    box:SetColorTexture(0.2, 0.2, 0.2, 0.8)
                end
            end
        end
    end

end
local anubisFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); anubisFrame:SetAllPoints(); anubisFrame:Hide()
do
    anubisFrame.title = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    anubisFrame.title:SetPoint("TOP", 0, -50); SetCustomFont(anubisFrame.title, 22, "OUTLINE"); GC_RegisterLocalizedFontString(anubisFrame.title, "LOC_GAME_HAND_OF_ANUBISATH")

    anubisFrame.statusText = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    anubisFrame.statusText:SetPoint("TOP", anubisFrame.title, "BOTTOM", 0, -5); SetCustomFont(anubisFrame.statusText, 14, "OUTLINE")
    anubisFrame.statusText:SetText(GC_L("LOC_2905"))

    anubisFrame.fsText = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    anubisFrame.fsText:SetPoint("TOP", anubisFrame.statusText, "BOTTOM", 0, -10)
    SetCustomFont(anubisFrame.fsText, 18, "OUTLINE")
    anubisFrame.fsText:SetTextColor(1, 0.2, 0.2)
    anubisFrame.fsText:SetText("")

    local ROWS, COLS = 6, 5 
    local CELL_SIZE = 48
    local FIXED_BET = 50 
    local MAX_WIN = FIXED_BET * 10000 

    anubisFrame.grid = CreateFrame("Frame", nil, anubisFrame, "BackdropTemplate")
    anubisFrame.grid:SetSize(COLS * (CELL_SIZE + 2) + 10, ROWS * (CELL_SIZE + 2) + 10)
    anubisFrame.grid:SetPoint("CENTER", 0, -10)
    anubisFrame.grid:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    anubisFrame.grid:SetBackdropColor(0.05, 0.05, 0.05, 0.9); anubisFrame.grid:SetBackdropBorderColor(0.8, 0.6, 0.1, 1)
    anubisFrame.grid:SetClipsChildren(true)

    anubisFrame.lifeContainer = CreateFrame("Frame", nil, anubisFrame)
    anubisFrame.lifeContainer:SetSize(260, 8)
    anubisFrame.lifeContainer:SetPoint("TOP", anubisFrame.grid, "BOTTOM", 0, -15)
    anubisFrame.lifeContainer:Hide()
    anubisFrame.lifeBars = {}

    local barWidth = 80
    local startX = -((3 * barWidth) + 20) / 2 + (barWidth / 2)
    for i = 1, 3 do
        local bar = anubisFrame.lifeContainer:CreateTexture(nil, "OVERLAY")
        bar:SetSize(barWidth, 8)
        bar:SetPoint("CENTER", anubisFrame.lifeContainer, "CENTER", startX + ((i - 1) * (barWidth + 10)), 0)
        bar:SetColorTexture(1, 0.8, 0, 1)
        anubisFrame.lifeBars[i] = bar
    end

    local function UpdateLifeBars()
        if bState ~= "JUDGMENT" then
            anubisFrame.lifeContainer:Hide()
            return
        end
        anubisFrame.lifeContainer:Show()
        for i = 1, 3 do
            if i <= bSpinsLeft then
                anubisFrame.lifeBars[i]:SetColorTexture(1, 0.8, 0, 1) 
            else
                anubisFrame.lifeBars[i]:SetColorTexture(0.2, 0.2, 0.2, 1) 
            end
        end
    end

    local function FlyAnim(startCell, targetFrame, text, r, g, b, size)
        local f = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
        f:SetText(text); f:SetTextColor(r or 1, g or 1, b or 1); SetCustomFont(f, size or 24, "OUTLINE")
        f:SetPoint("CENTER", startCell, "CENTER")

        local ag = f:CreateAnimationGroup()
        local move = ag:CreateAnimation("Translation")
        local startX, startY = startCell:GetCenter()
        local endX, endY = targetFrame:GetCenter()
        if startX and endX then
            move:SetOffset(endX - startX, endY - startY)
            move:SetDuration(0.6); move:SetSmoothing("IN_OUT")

            local fade = ag:CreateAnimation("Alpha")
            fade:SetFromAlpha(1); fade:SetToAlpha(0); fade:SetStartDelay(0.4); fade:SetDuration(0.2)

            ag:SetScript("OnFinished", function() f:Hide(); f:SetText("") end)
            ag:Play()
        else
            f:Hide()
        end
    end

    anubisFrame.colMultTexts = {}
    anubisFrame.colActiveTexts = {}
    anubisFrame.judgTopTexts = {}

    for c = 1, COLS do
        local m = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        m:SetPoint("TOP", anubisFrame.grid, "BOTTOMLEFT", (c-1)*(CELL_SIZE+2) + 5 + CELL_SIZE/2, -5)
        SetCustomFont(m, 16, "OUTLINE"); m:SetText("0"); m:Hide()
        anubisFrame.colMultTexts[c] = m
        
        local a = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        a:SetPoint("TOP", m, "BOTTOM", 0, -2)
        SetCustomFont(a, 12, "OUTLINE"); a:SetTextColor(0.2, 1, 0.2); GC_RegisterLocalizedFontString(a, "LOC_MANUAL_ACTIVE"); a:Hide()
        anubisFrame.colActiveTexts[c] = a

        local jt = anubisFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        jt:SetPoint("BOTTOM", anubisFrame.grid, "TOPLEFT", (c-1)*(CELL_SIZE+2) + 5 + CELL_SIZE/2, 5)
        SetCustomFont(jt, 18, "OUTLINE"); jt:SetTextColor(0.2, 0.8, 1); jt:SetText("0x"); jt:Hide()
        anubisFrame.judgTopTexts[c] = jt
    end
    anubisFrame.model = CreateFrame("PlayerModel", nil, anubisFrame)
    anubisFrame.model:SetSize(300, 340); anubisFrame.model:SetPoint("LEFT", anubisFrame, "CENTER", 100, -45)
    anubisFrame.model:SetDisplayInfo(15706) 
    if anubisFrame.model.SetAnimation then anubisFrame.model:SetAnimation(0) end
    anubisFrame.model:SetRotation(-0.5)

    anubisFrame.model2 = CreateFrame("PlayerModel", nil, anubisFrame)
    anubisFrame.model2:SetSize(300, 340)
    anubisFrame.model2:SetPoint("RIGHT", anubisFrame, "CENTER", -100, -45)
    anubisFrame.model2:SetDisplayInfo(15706) 
    if anubisFrame.model2.SetAnimation then anubisFrame.model2:SetAnimation(0) end
    anubisFrame.model2:SetRotation(0.5)

    local SYMBOLS = {
        {id=1, tex=134459, val=2.0}, {id=2, tex=134458, val=1.2}, {id=3, tex=134465, val=0.8},
        {id=4, tex=134461, val=0.5}, {id=5, tex=134455, val=0.3},
        {id=6, text="A", val=0.15}, {id=7, text="K", val=0.15}, {id=8, text="Q", val=0.1}, {id=9, text="J", val=0.1}, {id=10, text="10", val=0.1},
    }
    local SCATTER_TEX = "Interface\\Icons\\inv_misc_bone_skull_02"
    local SCATTER_ID = 50

    anubisFrame.paytable = CreateFrame("Frame", nil, anubisFrame, "BackdropTemplate")
    anubisFrame.paytable:SetSize(380, 260)
    anubisFrame.paytable:SetPoint("CENTER", anubisFrame.grid, "CENTER", 0, 0)
    anubisFrame.paytable:SetFrameLevel(anubisFrame.grid:GetFrameLevel() + 10)
    anubisFrame.paytable:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    anubisFrame.paytable:SetBackdropColor(0.05, 0.05, 0.05, 0.98); anubisFrame.paytable:SetBackdropBorderColor(0.8, 0.6, 0.1, 1)
    anubisFrame.paytable:Hide()

    anubisFrame.paytable.closeBtn = CreateFrame("Button", nil, anubisFrame.paytable, "UIPanelCloseButton")
    anubisFrame.paytable.closeBtn:SetPoint("TOPRIGHT", -2, -2)

    anubisFrame.ptTitle = anubisFrame.paytable:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    anubisFrame.ptTitle:SetPoint("TOP", 0, -15); SetCustomFont(anubisFrame.ptTitle, 16, "OUTLINE"); anubisFrame.ptTitle:SetText(GC_L("LOC_2977"))

    local leftY = -55
    for i = 1, 5 do
        local s = SYMBOLS[i]
        local tex = anubisFrame.paytable:CreateTexture(nil, "ARTWORK")
        tex:SetSize(26, 26); tex:SetPoint("TOPLEFT", 30, leftY); tex:SetTexture(s.tex)
        local valTxt = anubisFrame.paytable:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        valTxt:SetPoint("LEFT", tex, "RIGHT", 10, 0); SetCustomFont(valTxt, 13, "OUTLINE"); valTxt:SetText(GC_L("LOC_2985") .. math.floor(s.val * 25) .. GC_L("LOC_2986"))
        leftY = leftY - 35
    end

    local rightY = -55
    for i = 6, 10 do
        local s = SYMBOLS[i]
        local bg = anubisFrame.paytable:CreateTexture(nil, "ARTWORK")
        bg:SetSize(26, 26); bg:SetPoint("TOPLEFT", 200, rightY); bg:SetColorTexture(0.25, 0.25, 0.3, 1)
        local txt = anubisFrame.paytable:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        txt:SetPoint("CENTER", bg, "CENTER"); SetCustomFont(txt, 16, "OUTLINE"); txt:SetText(s.text)
        local valTxt = anubisFrame.paytable:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        valTxt:SetPoint("LEFT", bg, "RIGHT", 10, 0); SetCustomFont(valTxt, 13, "OUTLINE"); valTxt:SetText(GC_L("LOC_2999") .. math.floor(s.val * 25) .. GC_L("LOC_3000"))
        rightY = rightY - 35
    end

    local scatIcon = anubisFrame.paytable:CreateTexture(nil, "ARTWORK")
    scatIcon:SetSize(28, 28); scatIcon:SetPoint("TOPLEFT", 100, leftY - 10); scatIcon:SetTexture(SCATTER_TEX)
    
    local scatTxt = anubisFrame.paytable:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    scatTxt:SetPoint("LEFT", scatIcon, "RIGHT", 10, 0); SetCustomFont(scatTxt, 13, "OUTLINE")
    scatTxt:SetTextColor(0.2, 0.8, 1)
    scatTxt:SetText("3 = Underworld | 4 = Judgment")

    anubisFrame.cells = {}
    for r = 1, ROWS do
        anubisFrame.cells[r] = {}
        for c = 1, COLS do
            local f = CreateFrame("Frame", nil, anubisFrame.grid, "BackdropTemplate")
            f:SetSize(CELL_SIZE, CELL_SIZE); f:SetPoint("TOPLEFT", (c-1)*(CELL_SIZE+2) + 5, -(r-1)*(CELL_SIZE+2) - 5)
            
            f.symContainer = CreateFrame("Frame", nil, f)
            f.symContainer:SetAllPoints()

            f.tex = f.symContainer:CreateTexture(nil, "BACKGROUND")
            f.tex:SetAllPoints()

            f.symText = f.symContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
            f.symText:SetPoint("CENTER"); SetCustomFont(f.symText, 22, "OUTLINE"); f.symText:SetTextColor(1, 1, 1); f.symText:Hide()

            f.multText = f.symContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
            f.multText:SetPoint("CENTER"); SetCustomFont(f.multText, 18, "OUTLINE"); f.multText:Hide()

            f.glow = f.symContainer:CreateTexture(nil, "OVERLAY")
            f.glow:SetPoint("TOPLEFT", -4, 4)
            f.glow:SetPoint("BOTTOMRIGHT", 4, -4)
            f.glow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
            f.glow:SetBlendMode("ADD")
            f.glow:SetVertexColor(1, 0.8, 0, 1) 
            f.glow:Hide()

            f.dropAnim = f.symContainer:CreateAnimationGroup()
            f.instUp = f.dropAnim:CreateAnimation("Translation")
            f.instUp:SetOrder(1); f.instUp:SetDuration(0)
            f.dropDown = f.dropAnim:CreateAnimation("Translation")
            f.dropDown:SetOrder(2); f.dropDown:SetSmoothing("IN")

            anubisFrame.cells[r][c] = f
        end
    end

    local isSpinning, currentWin = false, 0
    bState = "NONE" 
    bSpinsLeft, bTotalMult, bTotalWin = 0, 0, 0
    local colMults = {0, 0, 0, 0, 0}; local colActive = {false, false, false, false, false}
    local judgColMults = {0, 0, 0, 0, 0}
    
    local domHigh, domLow = 1, 10

    local function SetCellSymbol(cell, symID, multVal)
        cell.symID = symID; cell.multVal = multVal
        if cell.glow then cell.glow:Hide() end 
        
        if symID == nil or symID == 0 then
            cell.symContainer:SetAlpha(0) 
            return
        end
        
        cell.symContainer:SetAlpha(1)
        cell.symText:Hide(); cell.multText:Hide(); cell.tex:SetColorTexture(0,0,0,0); cell.tex:SetTexture(nil)

        if symID == SCATTER_ID then cell.tex:SetTexture(SCATTER_TEX)
        elseif symID == 20 then cell.tex:SetTexture("Interface\\Icons\\inv_misc_gem_pearl_06")
        elseif symID == 21 then cell.tex:SetTexture("Interface\\Icons\\inv_misc_bone_skull_02")
        elseif symID == 30 then cell.tex:SetTexture("Interface\\Icons\\spell_ice_rune")
        elseif symID == 31 then cell.tex:SetTexture("Interface\\Icons\\inv_misc_bone_skull_02")
        elseif symID == 32 then cell.tex:SetTexture("Interface\\Icons\\inv_misc_bone_skull_01")
        elseif symID == 33 then cell.tex:SetTexture("Interface\\Icons\\inv_misc_bone_skull_03")
        elseif symID == 34 then cell.tex:SetTexture("Interface\\Icons\\inv_helm_armor_sugarskull_c_01")
        else
            local s = SYMBOLS[symID]
            if s then
                if s.text then
                    cell.tex:SetColorTexture(0.25, 0.25, 0.3, 1) 
                    cell.symText:SetText(s.text); cell.symText:Show()
                else cell.tex:SetTexture(s.tex) end
            end
        end
        
        if symID == 21 then cell.multText:SetText(multVal.."x"); cell.multText:SetTextColor(1,1,1); cell.multText:Show(); cell.symText:Hide()
        elseif symID >= 31 and symID <= 34 then cell.multText:SetText((symID >= 33 and "x" or "+")..multVal); cell.multText:SetTextColor(1,1,0); cell.multText:Show(); cell.symText:Hide()
        elseif symID == 30 and cell.locked then cell.multText:SetText(multVal.."x"); cell.multText:SetTextColor(0,1,1); cell.multText:Show(); cell.symText:Hide()
        end
    end

    local function UpdateUnderworldUI()
        for c=1, COLS do
            anubisFrame.colMultTexts[c]:SetText(colMults[c] > 0 and (colMults[c].."x") or "0")
            if colActive[c] then anubisFrame.colActiveTexts[c]:Show() else anubisFrame.colActiveTexts[c]:Hide() end
        end
    end

    local function GetRandomBaseSymbol(state, col)
        if state == "UNDERWORLD" then
            local r = math.random(1, 10000)
            if col and not colActive[col] and r > 9960 then return {id=20, val=0} 
            elseif col and colMults[col] > 0 and r > 9920 then 
                local mults = {2, 2, 2, 3, 3, 4, 5, 10}
                return {id=21, val=mults[math.random(1, 8)]} 
            end
        else
            if math.random(1, 1000) > 965 then return {id=SCATTER_ID, val=0} end
        end
        
        local r = math.random(1, 100)
        if r <= 15 then return SYMBOLS[domHigh]
        elseif r <= 30 then return SYMBOLS[domLow] end

        local rnd = math.random(1, 100)
        if rnd > 95 then return SYMBOLS[1] elseif rnd > 88 then return SYMBOLS[2] elseif rnd > 80 then return SYMBOLS[3] elseif rnd > 70 then return SYMBOLS[4] elseif rnd > 60 then return SYMBOLS[5] elseif rnd > 48 then return SYMBOLS[6] elseif rnd > 36 then return SYMBOLS[7] elseif rnd > 24 then return SYMBOLS[8] elseif rnd > 12 then return SYMBOLS[9] else return SYMBOLS[10] end
    end

    local function GetRandomJudgmentSymbol(col)
        local r = math.random(1, 1000)
        if judgColMults[col] == 0 then
            if r <= 850 then return {id=31, val=(math.random(1, 100) > 90) and math.random(4, 8) or math.random(1, 3)} 
            else return {id=32, val=math.random(1, 3)} end 
        else
            if r <= 600 then return {id=30, val=0} 
            elseif r <= 850 then return {id=31, val=(math.random(1, 100) > 90) and math.random(4, 10) or math.random(1, 4)} 
            elseif r <= 930 then return {id=32, val=math.random(1, 3)} 
            elseif r <= 985 then return {id=33, val=(math.random(1, 100) > 80) and 3 or 2} 
            else return {id=34, val=2} end 
        end
    end

    local function ApplyBaseGravity()
        local changed = false
        for c = 1, COLS do
            for r = ROWS, 2, -1 do
                if anubisFrame.cells[r][c].symID == nil or anubisFrame.cells[r][c].symID == 0 then
                    for ab = r - 1, 1, -1 do
                        local above = anubisFrame.cells[ab][c]
                        if above.symID and above.symID ~= 0 then
                            local dropDist = (r - ab) * (CELL_SIZE + 2)
                            SetCellSymbol(anubisFrame.cells[r][c], above.symID, above.multVal)
                            if anubisFrame.cells[r][c].dropAnim then
                                anubisFrame.cells[r][c].instUp:SetOffset(0, dropDist); anubisFrame.cells[r][c].dropDown:SetOffset(0, -dropDist); anubisFrame.cells[r][c].dropDown:SetDuration(0.3)
                                anubisFrame.cells[r][c].dropAnim:Stop(); anubisFrame.cells[r][c].dropAnim:Play()
                            end
                            SetCellSymbol(above, 0, 0); changed = true; break
                        end
                    end
                end
            end
            for r = ROWS, 1, -1 do
                if anubisFrame.cells[r][c].symID == nil or anubisFrame.cells[r][c].symID == 0 then
                    local sym = GetRandomBaseSymbol(bState, c)
                    local dropDist = r * (CELL_SIZE + 2)
                    SetCellSymbol(anubisFrame.cells[r][c], sym.id, sym.val)
                    if anubisFrame.cells[r][c].dropAnim then
                        anubisFrame.cells[r][c].instUp:SetOffset(0, dropDist); anubisFrame.cells[r][c].dropDown:SetOffset(0, -dropDist); anubisFrame.cells[r][c].dropDown:SetDuration(0.3)
                        anubisFrame.cells[r][c].dropAnim:Stop(); anubisFrame.cells[r][c].dropAnim:Play()
                    end
                    changed = true
                end
            end
        end
        if changed then 
            C_Timer.After(0.4, anubisFrame.CheckBaseWins) 
        end 
    end

    local function FindCluster(r, c, id, visited)
        if r < 1 or r > ROWS or c < 1 or c > COLS or visited[r][c] or anubisFrame.cells[r][c].symID ~= id or id > 10 then return 0, {} end
        visited[r][c] = true; local size, cluster = 1, {{r, c}}; local neighbors = {{r-1, c}, {r+1, c}, {r, c-1}, {r, c+1}}
        for _, n in ipairs(neighbors) do local s, cl = FindCluster(n[1], n[2], id, visited); size = size + s; for _, coord in ipairs(cl) do table.insert(cluster, coord) end end
        return size, cluster
    end

    function anubisFrame.CheckBaseWins()
        local visited = {}; for r=1, ROWS do visited[r] = {} end
        local clusterFound, specialFound, orbFound, scatters, tumbleWin = false, false, false, 0, 0
        local symbolsPerCol = {0,0,0,0,0}
        
        local cellsToGlow = {}
        local cellsToDestroy = {}

        for r=1, ROWS do for c=1, COLS do
            local cId = anubisFrame.cells[r][c].symID
            if cId == SCATTER_ID then scatters = scatters + 1 end
            if bState == "UNDERWORLD" then
                if cId == 20 then 
                    specialFound = true; orbFound = true; if not colActive[c] then colActive[c] = true; bSpinsLeft = bSpinsLeft + 3; FlyAnim(anubisFrame.cells[r][c], anubisFrame.fsText, GC_L("LOC_3046"), 0.2, 1, 0.2, 24) end
                    table.insert(cellsToDestroy, anubisFrame.cells[r][c])
                elseif cId == 21 then 
                    specialFound = true; 
                    if colMults[c] > 0 then 
                        colMults[c] = colMults[c] * anubisFrame.cells[r][c].multVal 
                        PlaySound(23197, "Master")
                        FlyAnim(anubisFrame.cells[r][c], anubisFrame.colMultTexts[c], "x" .. anubisFrame.cells[r][c].multVal, 1, 1, 1, 20)
                    end
                    table.insert(cellsToDestroy, anubisFrame.cells[r][c])
                end
            end
            if not visited[r][c] and cId and cId <= 10 then
                local size, cluster = FindCluster(r, c, cId, visited)
                if size >= 5 then
                    clusterFound = true
                    local baseVal = SYMBOLS[cId].val
                    tumbleWin = tumbleWin + math.floor(size * baseVal * (FIXED_BET / 10))
                    for _, coord in ipairs(cluster) do 
                        symbolsPerCol[coord[2]] = symbolsPerCol[coord[2]] + 1
                        table.insert(cellsToGlow, anubisFrame.cells[coord[1]][coord[2]])
                    end
                end
            end
        end end

        if bState == "UNDERWORLD" then
            for c=1, COLS do colMults[c] = colMults[c] + symbolsPerCol[c] end
            UpdateUnderworldUI()
            if clusterFound then
                local globalActiveMult = 0; for c=1, COLS do if colActive[c] then globalActiveMult = globalActiveMult + colMults[c] end end
                if globalActiveMult > 0 then tumbleWin = tumbleWin * globalActiveMult end
            end
        end

        if clusterFound or specialFound then 
            if clusterFound or orbFound then
                PlaySound(1210, "Master")
            end
            
            if clusterFound then
                currentWin = currentWin + tumbleWin
                if bState == "UNDERWORLD" and (bTotalWin + currentWin) >= MAX_WIN then currentWin = MAX_WIN - bTotalWin; bSpinsLeft = 0; anubisFrame.statusText:SetText(GC_L("LOC_3052")) else anubisFrame.statusText:SetText(GC_L("LOC_3053") .. currentWin .. "|r") end
                
                for _, cell in ipairs(cellsToGlow) do
                    if cell.glow then cell.glow:Show() end
                end
            end
            if bState == "UNDERWORLD" then anubisFrame.fsText:SetText(GC_L("LOC_3056") .. bSpinsLeft .. GC_L("LOC_3057") .. (bTotalWin + currentWin)) end
            
            C_Timer.After(0.5, function() 
                for _, cell in ipairs(cellsToGlow) do SetCellSymbol(cell, 0, 0) end
                for _, cell in ipairs(cellsToDestroy) do SetCellSymbol(cell, 0, 0) end
                ApplyBaseGravity()
            end)
        else 
            if scatters >= 4 and bState == "NONE" then 
                bState = "JUDGMENT"; bSpinsLeft = 3; bTotalMult = 0; judgColMults = {0,0,0,0,0}
                for c=1, COLS do anubisFrame.judgTopTexts[c]:Show(); anubisFrame.judgTopTexts[c]:SetText("0x") end
                UpdateLifeBars()
                anubisFrame.fsText:SetText(GC_L("LOC_3061")); PlaySound(8440); C_Timer.After(2, anubisFrame.DoSpin)
            elseif scatters == 3 and bState == "NONE" then 
                bState = "UNDERWORLD"; bSpinsLeft = 10; colMults = {0,0,0,0,0}; colActive = {false,false,false,false,false}; for c=1, COLS do anubisFrame.colMultTexts[c]:Show() end; UpdateUnderworldUI()
                anubisFrame.fsText:SetText(GC_L("LOC_3064")); PlaySound(8440); C_Timer.After(2, anubisFrame.DoSpin)
            else anubisFrame.Finalize() end 
        end
    end

    function anubisFrame.DoBaseSpin()
        isSpinning = true; anubisFrame.spinBtn:Disable(); currentWin = 0
        domHigh = math.random(1, 5); domLow = math.random(6, 10) 
        
        if bState == "UNDERWORLD" then 
            bSpinsLeft = bSpinsLeft - 1; anubisFrame.fsText:SetText(GC_L("LOC_3066") .. bSpinsLeft .. GC_L("LOC_3067") .. bTotalWin); anubisFrame.statusText:SetText(GC_L("LOC_3068"))
        else
            if playChips < FIXED_BET then anubisFrame.statusText:SetText(GC_L("LOC_3069")); isSpinning = false; anubisFrame.spinBtn:Enable(); return end
            UpdatePlayChips(-FIXED_BET); anubisFrame.statusText:SetText(GC_L("LOC_3070")); bTotalWin = 0; anubisFrame.fsText:SetText("")
        end
        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        for r = 1, ROWS do for c = 1, COLS do SetCellSymbol(anubisFrame.cells[r][c], 0, 0) end end
        for c = 1, COLS do C_Timer.After((c - 1) * 0.1, function()
            for r = ROWS, 1, -1 do C_Timer.After((ROWS - r) * 0.08, function()
                local sym = GetRandomBaseSymbol(bState, c)
                SetCellSymbol(anubisFrame.cells[r][c], sym.id, sym.val)
                local dropDist = r * (CELL_SIZE + 2)
                if anubisFrame.cells[r][c].dropAnim and sym.id ~= 0 then anubisFrame.cells[r][c].instUp:SetOffset(0, dropDist); anubisFrame.cells[r][c].dropDown:SetOffset(0, -dropDist); anubisFrame.cells[r][c].dropDown:SetDuration(0.2); anubisFrame.cells[r][c].dropAnim:Stop(); anubisFrame.cells[r][c].dropAnim:Play() end
            end) end
            if c == COLS then 
                C_Timer.After(0.8, anubisFrame.CheckBaseWins) 
            end
        end) end
    end

    function anubisFrame.DoJudgmentSpin()
        isSpinning = true; bSpinsLeft = bSpinsLeft - 1
        anubisFrame.fsText:SetText(GC_L("LOC_3073") .. bTotalMult .. "x")
        UpdateLifeBars() 
        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")

        local landedAny = false; local symbolsToProcess = {}

        for c = 1, COLS do
            local emptyRow = nil
            for r = ROWS, 1, -1 do if not anubisFrame.cells[r][c].locked then emptyRow = r; break end end
            if emptyRow and math.random(1, 100) <= 14 then
                local sym = GetRandomJudgmentSymbol(c) 
                if sym.id ~= 0 then landedAny = true; table.insert(symbolsToProcess, {col = c, targetRow = emptyRow, sym = sym}) end
            end
        end

        if landedAny then
            for _, drop in ipairs(symbolsToProcess) do
                local c = drop.col; local r = drop.targetRow; local sym = drop.sym; local cell = anubisFrame.cells[r][c]
                SetCellSymbol(cell, sym.id, sym.val)
                local dropDist = r * (CELL_SIZE + 2)
                cell.instUp:SetOffset(0, dropDist); cell.dropDown:SetOffset(0, -dropDist); cell.dropDown:SetDuration(0.4) 
                cell.dropAnim:Stop(); cell.dropAnim:Play()
            end

            C_Timer.After(0.8, function() 
                local blocksLocked = false
                local multAdded = false
                for _, drop in ipairs(symbolsToProcess) do
                    local c = drop.col; local r = drop.targetRow; local sym = drop.sym; local cell = anubisFrame.cells[r][c]

                    if sym.id == 30 then 
                        cell.locked = true; SetCellSymbol(cell, 30, judgColMults[c])
                        bTotalMult = bTotalMult + judgColMults[c]; blocksLocked = true
                    elseif sym.id == 31 then 
                        judgColMults[c] = judgColMults[c] + sym.val; SetCellSymbol(cell, 0, 0); multAdded = true
                        FlyAnim(cell, anubisFrame.judgTopTexts[c], "+" .. sym.val, 1, 1, 0, 20)
                    elseif sym.id == 32 then 
                        for i=1, COLS do judgColMults[i] = judgColMults[i] + sym.val; FlyAnim(cell, anubisFrame.judgTopTexts[i], "+" .. sym.val, 1, 1, 0, 20) end; SetCellSymbol(cell, 0, 0); multAdded = true
                    elseif sym.id == 33 then 
                        if judgColMults[c] > 0 then judgColMults[c] = judgColMults[c] * sym.val; FlyAnim(cell, anubisFrame.judgTopTexts[c], "x" .. sym.val, 1, 1, 1, 20) end; SetCellSymbol(cell, 0, 0); multAdded = true
                    elseif sym.id == 34 then 
                        for i=1, COLS do if judgColMults[i] > 0 then judgColMults[i] = judgColMults[i] * sym.val; FlyAnim(cell, anubisFrame.judgTopTexts[i], "x" .. sym.val, 1, 1, 1, 20) end end; SetCellSymbol(cell, 0, 0); multAdded = true
                    end
                end

                for i=1, COLS do anubisFrame.judgTopTexts[i]:SetText(judgColMults[i] .. "x") end
                
                if blocksLocked then PlaySound(8440) 
                elseif multAdded then PlaySound(23197, "Master")
                else PlaySound(1210) end
                
                bSpinsLeft = 3 
                anubisFrame.fsText:SetText(GC_L("LOC_3082") .. bTotalMult .. "x")
                UpdateLifeBars() 

                C_Timer.After(1.5, function() 
                    local allFull = true; for c=1, COLS do for r=1, ROWS do if not anubisFrame.cells[r][c].locked then allFull = false; break end end end
                    if bSpinsLeft <= 0 or allFull then anubisFrame.Finalize() else anubisFrame.DoJudgmentSpin() end
                end)
            end)
        else C_Timer.After(1.0, function() if bSpinsLeft <= 0 then anubisFrame.Finalize() else anubisFrame.DoJudgmentSpin() end end) end
    end

    function anubisFrame.DoSpin()
        if bState == "JUDGMENT" then
            for r = 1, ROWS do for c = 1, COLS do if not anubisFrame.cells[r][c].locked then SetCellSymbol(anubisFrame.cells[r][c], 0, 0) end end end
            anubisFrame.DoJudgmentSpin()
        else anubisFrame.DoBaseSpin() end
    end

    function anubisFrame.Finalize()
        if bState == "UNDERWORLD" then
            bTotalWin = bTotalWin + currentWin; currentWin = 0
            if bSpinsLeft > 0 and bTotalWin < MAX_WIN then C_Timer.After(1.5, anubisFrame.DoSpin) return else
                bState = "NONE"; if bTotalWin > 0 then UpdatePlayChips(bTotalWin); AddChipTransaction(CleanName(UnitName("player")), bTotalWin, "Anubisath Underworld"); AnnounceGameWin("Anubisath Underworld", bTotalWin); anubisFrame.statusText:SetText(GC_L("LOC_3090") .. bTotalWin .. GC_L("LOC_3091")) end
                anubisFrame.fsText:SetText(""); for c=1, COLS do anubisFrame.colMultTexts[c]:Hide(); anubisFrame.colActiveTexts[c]:Hide() end
            end
        elseif bState == "JUDGMENT" then
            bState = "NONE"; bTotalWin = math.floor(FIXED_BET * bTotalMult); if bTotalWin > MAX_WIN then bTotalWin = MAX_WIN end
            if bTotalWin > 0 then UpdatePlayChips(bTotalWin); AddChipTransaction(CleanName(UnitName("player")), bTotalWin, "Anubisath Judgment"); AnnounceGameWin("Anubisath Judgment", bTotalWin); anubisFrame.statusText:SetText(GC_L("LOC_3098")..bTotalMult.."x (" .. bTotalWin .. GC_L("LOC_3100")) end
            anubisFrame.fsText:SetText(""); for c=1, COLS do anubisFrame.judgTopTexts[c]:Hide() end
            for r=1, ROWS do for c=1, COLS do anubisFrame.cells[r][c].locked = false end end
            UpdateLifeBars() 
        else
            if currentWin > 0 then UpdatePlayChips(currentWin); AddChipTransaction(CleanName(UnitName("player")), currentWin, "Hand of Anubisath"); AnnounceGameWin("Hand of Anubisath", currentWin)
            else AddChipTransaction(CleanName(UnitName("player")), -FIXED_BET, "Hand of Anubisath"); anubisFrame.statusText:SetText(GC_L("LOC_3107")) end
        end
        isSpinning = false; anubisFrame.spinBtn:Enable()
    end

    anubisFrame.spinBtn = CreateLocalizedButton(anubisFrame, "LOC_3108", 150, 40)
    anubisFrame.spinBtn:SetPoint("BOTTOM", 20, 38) 
    anubisFrame.spinBtn:SetScript("OnClick", function() if not isSpinning then anubisFrame.DoSpin() end end)

    anubisFrame.infoBtn = CreateLocalizedButton(anubisFrame, "LOC_3111", 80, 40)
    anubisFrame.infoBtn:SetPoint("RIGHT", anubisFrame.spinBtn, "LEFT", -10, 0)
    anubisFrame.infoBtn:SetScript("OnClick", function()
        if anubisFrame.paytable:IsShown() then anubisFrame.paytable:Hide() else anubisFrame.paytable:Show() end
    end)
end

local wantedSlotFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay); wantedSlotFrame:SetAllPoints(); wantedSlotFrame:Hide()
do
    wantedSlotFrame.title = wantedSlotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    wantedSlotFrame.title:SetPoint("TOP", 0, -70); SetCustomFont(wantedSlotFrame.title, 24, "OUTLINE")
    GC_RegisterLocalizedFontString(wantedSlotFrame.title, "LOC_GAME_WANTED"); wantedSlotFrame.title:SetTextColor(1, 0.6, 0)
    wantedSlotFrame.result = wantedSlotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    wantedSlotFrame.result:SetPoint("BOTTOM", wantedSlotFrame, "CENTER", 0, 110)
    SetCustomFont(wantedSlotFrame.result, 20, "OUTLINE"); wantedSlotFrame.result:SetText(GC_L("LOC_3126"))
    wantedSlotFrame.spinBtn = CreateLocalizedButton(wantedSlotFrame, "LOC_3127", 160, 40)
    wantedSlotFrame.spinBtn:SetPoint("BOTTOM", wantedSlotFrame, "BOTTOM", 50, 40)
    wantedSlotFrame.spinBtn.bg:SetColorTexture(0.6, 0.1, 0.1, 0.9)
    local infoBtn = CreateLocalizedButton(wantedSlotFrame, "LOC_3130", 80, 40)
    infoBtn:SetPoint("RIGHT", wantedSlotFrame.spinBtn, "LEFT", -10, 0)
    wantedSlotFrame.infoPanel = CreateFrame("Frame", nil, wantedSlotFrame, "BackdropTemplate")
    wantedSlotFrame.infoPanel:SetSize(420, 520)
    wantedSlotFrame.infoPanel:SetPoint("CENTER", wantedSlotFrame, "CENTER", 0, 0)
    wantedSlotFrame.infoPanel:SetFrameStrata("FULLSCREEN_DIALOG") 
    wantedSlotFrame.infoPanel:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = {left = 4, right = 4, top = 4, bottom = 4}})
    wantedSlotFrame.infoPanel:SetBackdropColor(0.05, 0.05, 0.05, 1)
    wantedSlotFrame.infoPanel:Hide()
    local closeInfoBtn = CreateFrame("Button", nil, wantedSlotFrame.infoPanel, "UIPanelCloseButton")
    closeInfoBtn:SetPoint("TOPRIGHT", wantedSlotFrame.infoPanel, "TOPRIGHT", -5, -5)
    closeInfoBtn:SetScript("OnClick", function() wantedSlotFrame.infoPanel:Hide() end)
    infoBtn:SetScript("OnClick", function() wantedSlotFrame.infoPanel:Show() end)
    local infoTitle = wantedSlotFrame.infoPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    infoTitle:SetPoint("TOP", 0, -15); SetCustomFont(infoTitle, 18, "OUTLINE"); infoTitle:SetText(GC_L("LOC_3150"))
    local infoText = wantedSlotFrame.infoPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    infoText:SetPoint("TOPLEFT", 15, -45); infoText:SetWidth(390); infoText:SetJustifyH("LEFT"); infoText:SetJustifyV("TOP")
    SetCustomFont(infoText, 13, "OUTLINE")
    infoText:SetText(
        GC_L("LOC_3157") ..
        GC_L("LOC_3158") ..
        GC_L("LOC_3159") ..
        GC_L("LOC_3160") ..
        GC_L("LOC_3161") ..
        GC_L("LOC_3162") ..
        GC_L("LOC_3163") ..
        GC_L("LOC_3164") ..
        GC_L("LOC_3165") ..
        GC_L("LOC_3166") ..
        GC_L("LOC_3167") ..
        GC_L("LOC_3168") ..
        GC_L("LOC_3169") ..
        GC_L("LOC_3170")
    )

    local symbols = {
    { id = 1, tex = "Interface\\Icons\\INV_Weapon_Rifle_01", pays = {50, 150, 500} },
    { id = 2, tex = "Interface\\Icons\\INV_Misc_Bag_10", pays = {40, 100, 300} }, 
    { id = 3, tex = "Interface\\Icons\\INV_Drink_05", pays = {25, 75, 200} },
    { id = 4, tex = "Interface\\Icons\\INV_Misc_Bandana_03", pays = {15, 40, 100} },
    { id = "WILD", isWild = true, isText = true, text = "WILD", color = {1, 0.8, 0}, bg = {0.1, 0.1, 0.1}, pays = {100, 250, 1000} },

    { id = "VS", isVS = true, isText = true, text = "VS", color = {1, 0, 0}, bg = {0.8, 0.6, 0} },
    { id = "TRAIN", isScatter = true, isText = true, text = "TRAIN", color = {0, 1, 0}, bg = {0.1, 0.3, 0.1} },
    { id = "DUEL", isScatter = true, isText = true, text = "DUEL", color = {1, 0.5, 0}, bg = {0.4, 0.2, 0.1} },
    { id = "DEAD", isScatter = true, isText = true, text = "DEAD", color = {0.8, 0.8, 0.8}, bg = {0.2, 0.2, 0.2} },
    { id = "BLANK", isText = true, text = "X", color = {0.3, 0.3, 0.3}, bg = {0.05, 0.05, 0.05} },
    { id = "DMH_WILD", isText = true, text = "+1 W", color = {1, 0.8, 0}, bg = {0.3, 0.2, 0} },
    { id = "DMH_MULT", isText = true, text = "+ MULT", color = {1, 0, 0}, bg = {0.3, 0, 0} },

    { id = "A", isCard = true, isText = true, text = "A", color = {0.1, 0.1, 0.1}, bg = {0.85, 0.80, 0.72}, pays = {5, 12, 50} },
    { id = "K", isCard = true, isText = true, text = "K", color = {0.1, 0.1, 0.1}, bg = {0.85, 0.80, 0.72}, pays = {5, 12, 50} },
    { id = "Q", isCard = true, isText = true, text = "Q", color = {0.1, 0.1, 0.1}, bg = {0.85, 0.80, 0.72}, pays = {5, 12, 50} },
    { id = "J", isCard = true, isText = true, text = "J", color = {0.1, 0.1, 0.1}, bg = {0.85, 0.80, 0.72}, pays = {5, 12, 50} },
    { id = "10", isCard = true, isText = true, text = "10", color = {0.1, 0.1, 0.1}, bg = {0.85, 0.80, 0.72}, pays = {5, 12, 50} }
}
    
    local function CreatePool(mode)
        local pool = {}
        if mode == "DEAD_PHASE1" then
            for i=1, 200 do table.insert(pool, symbols[10]) end
            for i=1, 3 do table.insert(pool, symbols[11]) end
            for i=1, 3 do table.insert(pool, symbols[12]) end
            return pool
        end
        
        for i=1, 20 do table.insert(pool, symbols[13]) end
        for i=1, 20 do table.insert(pool, symbols[14]) end
        for i=1, 20 do table.insert(pool, symbols[15]) end
        for i=1, 20 do table.insert(pool, symbols[16]) end
        for i=1, 20 do table.insert(pool, symbols[17]) end
        
        for i=1, 15 do table.insert(pool, symbols[4]) end
        for i=1, 12 do table.insert(pool, symbols[3]) end
        for i=1, 10 do table.insert(pool, symbols[2]) end
        for i=1, 8 do table.insert(pool, symbols[1]) end
        
        local wildC, vsC = 6, 2
        if mode == "DUEL" then 
            vsC = 5
        elseif mode == "TRAIN" then
            vsC = 0
        end
        
        for i=1, wildC do table.insert(pool, symbols[5]) end 
        for i=1, vsC do table.insert(pool, symbols[6]) end 
        
        if mode == "BASE" then
            for i=1, 7 do table.insert(pool, symbols[7]) end 
            for i=1, 5 do table.insert(pool, symbols[8]) end 
            for i=1, 3 do table.insert(pool, symbols[9]) end 
        end
        return pool
    end
    
    wantedSlotFrame.boxes = {}; wantedSlotFrame.boxTexts = {}
    local rows, cols, iconSize, spacing = 5, 5, 65, 70
    local startX = -((cols-1)*spacing)/2; local startY = 60
    
    local function SetBlockVisual(f, t, sym)
        if sym.id == "WILD" then f.goldBorder:Show() else f.goldBorder:Hide() end
        
        if sym.isCard then 
            f.cardBg:Show() 
            f:SetColorTexture(0.1, 0.1, 0.1, 1)
        else 
            f.cardBg:Hide() 
        end

        if sym.isText then 
            if not sym.isCard then f:SetColorTexture(unpack(sym.bg)) end
            
            t:SetText(sym.text)
            t:SetTextColor(unpack(sym.color))
            
            if sym.isCard then
                SetCustomFont(t, 34, "")
            elseif sym.id == "WILD" or sym.id == "VS" then
                SetCustomFont(t, 22, "OUTLINE") 
            else
                SetCustomFont(t, 16, "OUTLINE") 
            end
        else 
            f:SetColorTexture(1, 1, 1, 1)
            f:SetTexture(sym.tex)
            t:SetText("") 
        end
    end

    for row = 1, rows do
        wantedSlotFrame.boxes[row] = {}; wantedSlotFrame.boxTexts[row] = {}
        for col = 1, cols do
            local bgBorder = wantedSlotFrame:CreateTexture(nil, "BACKGROUND")
            bgBorder:SetSize(iconSize + 6, iconSize + 6)
            bgBorder:SetPoint("CENTER", wantedSlotFrame, "CENTER", startX + ((col - 1) * spacing), startY - ((row - 1) * spacing))
            bgBorder:SetColorTexture(1, 0.84, 0, 1)
            bgBorder:Hide()

            local f = wantedSlotFrame:CreateTexture(nil, "ARTWORK", nil, 1)
            f:SetSize(iconSize, iconSize)
            f:SetPoint("CENTER", wantedSlotFrame, "CENTER", startX + ((col - 1) * spacing), startY - ((row - 1) * spacing))
            f.goldBorder = bgBorder
            
            local cardBg = wantedSlotFrame:CreateTexture(nil, "ARTWORK", nil, 2)
            cardBg:SetSize(42, 55)
            cardBg:SetPoint("CENTER", f, "CENTER")
            cardBg:SetColorTexture(0.85, 0.80, 0.72, 1)
            cardBg:Hide()
            f.cardBg = cardBg

            wantedSlotFrame.boxes[row][col] = f
            local t = wantedSlotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            t:SetPoint("CENTER", f, "CENTER")
            wantedSlotFrame.boxTexts[row][col] = t
            
            SetBlockVisual(f, t, symbols[4])
        end
    end

    wantedSlotFrame.vsCols = {}
    for col = 1, cols do
        local vsContainer = CreateFrame("Frame", nil, wantedSlotFrame)
        vsContainer:SetSize(iconSize + 8, rows * spacing + 4); vsContainer:SetPoint("CENTER", wantedSlotFrame, "CENTER", startX + ((col - 1) * spacing), startY - ((rows - 1) * spacing)/2); vsContainer:Hide()
        
        local vsBorder = vsContainer:CreateTexture(nil, "BACKGROUND")
        vsBorder:SetColorTexture(1, 0.84, 0, 0.8); vsBorder:SetAllPoints(vsContainer); vsContainer.border = vsBorder

        local vsTex = vsContainer:CreateTexture(nil, "ARTWORK")
        vsTex:SetColorTexture(0.2, 0.02, 0.02, 0.95); vsTex:SetPoint("CENTER"); vsTex:SetWidth(iconSize + 4); vsTex:SetHeight(iconSize); vsContainer.tex = vsTex
        
        local vsText = vsContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        vsText:SetPoint("CENTER", vsTex, "CENTER"); SetCustomFont(vsText, 46, "OUTLINE"); vsText:SetTextColor(1, 0.8, 0); vsText:SetText("VS"); vsContainer.text = vsText
        
        local topMult = vsContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        topMult:SetPoint("TOP", vsTex, "TOP", 0, -20); SetCustomFont(topMult, 28, "OUTLINE"); topMult:SetTextColor(1, 1, 1); topMult:Hide(); vsContainer.topMult = topMult
        
        local botMult = vsContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        botMult:SetPoint("BOTTOM", vsTex, "BOTTOM", 0, 20); SetCustomFont(botMult, 28, "OUTLINE"); botMult:SetTextColor(1, 1, 1); botMult:Hide(); vsContainer.botMult = botMult
        
        local multText = vsContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); multText:SetPoint("CENTER", vsTex, "CENTER", 0, -10); SetCustomFont(multText, 36, "OUTLINE"); multText:SetTextColor(1, 0.8, 0); multText:Hide(); vsContainer.multText = multText
        
        wantedSlotFrame.vsCols[col] = vsContainer
    end

    wantedSlotFrame.livesContainer = CreateFrame("Frame", nil, wantedSlotFrame)
    wantedSlotFrame.livesContainer:SetSize(50, 180)
    wantedSlotFrame.livesContainer:SetPoint("CENTER", wantedSlotFrame, "CENTER", 220, startY - (spacing*2)) 
    wantedSlotFrame.livesContainer:Hide()
    
    wantedSlotFrame.lives = {}
    for i=1, 3 do
        local bg = wantedSlotFrame.livesContainer:CreateTexture(nil, "BACKGROUND")
        bg:SetSize(40, 40)
        bg:SetPoint("TOP", 0, -(i-1)*55)
        bg:SetColorTexture(0.1, 0.1, 0.1, 0.8) 
        
        local tex = wantedSlotFrame.livesContainer:CreateTexture(nil, "ARTWORK")
        tex:SetSize(34, 34)
        tex:SetPoint("CENTER", bg, "CENTER")
        tex:SetTexture("Interface\\Icons\\INV_Ammo_Bullet_02") 
        wantedSlotFrame.lives[i] = tex
    end
    
    local function UpdateLivesUI(lives)
        for i=1, 3 do
            if i <= lives then
                wantedSlotFrame.lives[i]:SetVertexColor(1, 1, 1, 1) 
            else
                wantedSlotFrame.lives[i]:SetVertexColor(0.2, 0.2, 0.2, 0.5) 
            end
        end
    end

    local function GetWinningVSMult()
        local p = {
            2,2,2,2,2,2,2,2,2,2,
            3,3,3,3,3,3,3,3,
            4,4,4,4,4,4,
            5,5,5,5,
            6,6,
            7, 8, 9, 10, 11, 12, 25, 50, 75, 100
        }
        return p[math.random(1, #p)]
    end

    local function GetFakeVSMult(excludeMult)
        local p = {2,3,4,5,6,7,8,9,10,11,11,12,12,12,25,25, 50,50,50, 75,75,75, 100,100,100}
        local r = p[math.random(1, #p)]
        while r == excludeMult do r = p[math.random(1, #p)] end
        return r
    end

    wantedSlotFrame.lineSegments = {}
    local function GetLineSegment(idx)
        if not wantedSlotFrame.lineSegments[idx] then
            local line = wantedSlotFrame:CreateLine(nil, "OVERLAY")
            line:SetColorTexture(1, 0, 0, 0.9); line:SetThickness(5)
            wantedSlotFrame.lineSegments[idx] = line
        end
        return wantedSlotFrame.lineSegments[idx]
    end

    local paylines = {{{1,1},{1,2},{1,3},{1,4},{1,5}}, {{2,1},{2,2},{2,3},{2,4},{2,5}}, {{3,1},{3,2},{3,3},{3,4},{3,5}}, {{4,1},{4,2},{4,3},{4,4},{4,5}}, {{5,1},{5,2},{5,3},{5,4},{5,5}}, {{1,1},{2,2},{3,3},{4,4},{5,5}}, {{5,1},{4,2},{3,3},{2,4},{1,5}}, {{2,1},{1,2},{1,3},{1,4},{2,5}}, {{4,1},{5,2},{5,3},{5,4},{4,5}}, {{3,1},{2,2},{1,3},{2,4},{3,5}}, {{3,1},{4,2},{5,3},{4,4},{3,5}}, {{1,1},{2,2},{1,3},{2,4},{1,5}}, {{5,1},{4,2},{5,3},{4,4},{5,5}}, {{2,1},{3,2},{2,3},{3,4},{2,5}}, {{4,1},{3,2},{4,3},{3,4},{4,5}}}
    
    local state = { mode = "BASE", spins = 0, sticky = {}, dmhWilds = 0, dmhMult = 1, dmhLives = 3, bonusTotalWin = 0 }
    local MAX_WIN_LIMIT = 300000

    local function DoSpin()
        if wantedSlotFrame.isSpinning then return end
        
        if state.mode == "BASE" then
            if playChips < 100 then wantedSlotFrame.result:SetText(GC_L("LOC_3264")); return end
            UpdatePlayChips(-100); wantedSlotFrame.result:SetText(GC_L("LOC_3265"))
        elseif state.mode == "DEAD_PHASE1" then
            state.dmhLives = state.dmhLives - 1
            UpdateLivesUI(state.dmhLives)
            wantedSlotFrame.result:SetText(GC_L("LOC_3267") .. state.dmhLives .. GC_L("LOC_3268") .. state.dmhWilds .. GC_L("LOC_3269") .. state.dmhMult .. "x")
        else
            state.spins = state.spins - 1
            local mText = state.mode
            if state.mode == "DEAD_PHASE2" then mText = "SHOWDOWN" end
            wantedSlotFrame.result:SetText("|cFF00FFFF" .. mText .. GC_L("LOC_3274") .. state.spins .. GC_L("LOC_3275") .. state.bonusTotalWin)
        end
        
        wantedSlotFrame.isSpinning = true; wantedSlotFrame.spinBtn:Disable()
        for _, l in pairs(wantedSlotFrame.lineSegments) do l:Hide() end
        for col = 1, cols do
            wantedSlotFrame.vsCols[col]:Hide()
            wantedSlotFrame.vsCols[col].text:Hide()
            wantedSlotFrame.vsCols[col].topMult:Hide()
            wantedSlotFrame.vsCols[col].botMult:Hide()
            wantedSlotFrame.vsCols[col].multText:Hide()
        end
        for r = 1, rows do for c = 1, cols do wantedSlotFrame.boxes[r][c]:SetVertexColor(1,1,1,1) end end
        
        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        
        local activePool = CreatePool(state.mode)
        
        local results = {}
        for r = 1, rows do results[r] = {} end
        for c = 1, cols do
            local vsCountInCol = 0
            for r = 1, rows do
                local sym = activePool[math.random(1, #activePool)]
                while sym.id == "VS" and vsCountInCol >= 1 do sym = activePool[math.random(1, #activePool)] end
                if sym.id == "VS" then vsCountInCol = 1 end
                results[r][c] = sym
            end
        end
        
        if state.mode == "DEAD_PHASE2" then
            local wPlaced = 0
            while wPlaced < state.dmhWilds and wPlaced < 25 do
                local rr, cc = math.random(1, rows), math.random(1, cols)
                if not results[rr][cc].isWild then results[rr][cc] = symbols[5]; wPlaced = wPlaced + 1 end
            end
        end

        local tick = 0
        local function SpinAnim()
            tick = tick + 1
            for col = 1, cols do
                local stopTick = col * 8
                if tick < stopTick then
                    for row = 1, rows do 
                        local spinSym = activePool[math.random(1, #activePool)]
                        if state.mode == "TRAIN" and state.sticky[row.."_"..col] then
                            spinSym = symbols[5] 
                        end
                        SetBlockVisual(wantedSlotFrame.boxes[row][col], wantedSlotFrame.boxTexts[row][col], spinSym) 
                    end
                elseif tick == stopTick then
                    local playHitSound = false
                    for row = 1, rows do
                        local displaySym = results[row][col]
                        
                        if state.mode == "TRAIN" then
                            if displaySym.id == "WILD" and not state.sticky[row.."_"..col] then playHitSound = true end
                            if state.sticky[row.."_"..col] then displaySym = symbols[5] end 
                        elseif state.mode == "DEAD_PHASE1" then
                            if displaySym.id == "DMH_WILD" or displaySym.id == "DMH_MULT" then playHitSound = true end
                        elseif state.mode == "DEAD_PHASE2" then
                            if displaySym.id == "WILD" then playHitSound = true end
                        end
                        
                        SetBlockVisual(wantedSlotFrame.boxes[row][col], wantedSlotFrame.boxTexts[row][col], displaySym)
                    end
                    PlaySound(856)
                    if playHitSound then PlaySound(1210, "Master") end
                end
            end
            
            if tick < cols * 8 then C_Timer.After(0.05, SpinAnim) else
                
                if state.mode == "DEAD_PHASE1" then
                    local hit = false
                    for r=1, rows do for c=1, cols do
                        if results[r][c].id == "DMH_WILD" then state.dmhWilds = state.dmhWilds + 1; hit = true
                        elseif results[r][c].id == "DMH_MULT" then state.dmhMult = state.dmhMult + 1; hit = true end
                    end end
                    
                    if hit then 
                        state.dmhLives = 3; 
                        UpdateLivesUI(3) 
                        PlaySound(8440) 
                    end
                    wantedSlotFrame.result:SetText(GC_L("LOC_3295") .. state.dmhLives .. GC_L("LOC_3296") .. state.dmhWilds .. GC_L("LOC_3297") .. state.dmhMult .. "x")
                    
                    if state.dmhLives <= 0 then
                        state.mode = "DEAD_PHASE2"; state.spins = 3
                        wantedSlotFrame.livesContainer:Hide() 
                        wantedSlotFrame.result:SetText("|cFFFF0000SHOWDOWN!|r " .. state.dmhWilds .. GC_L("LOC_3301") .. state.dmhMult .. GC_L("LOC_3302"))
                        PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                        C_Timer.After(2.5, function() wantedSlotFrame.isSpinning = false; wantedSlotFrame.spinBtn:Enable(); DoSpin() end)
                    else
                        wantedSlotFrame.isSpinning = false; wantedSlotFrame.spinBtn:Enable(); C_Timer.After(1.0, DoSpin)
                    end
                    return
                end

                if state.mode == "TRAIN" then
                    for r=1, rows do for c=1, cols do
                        if results[r][c].id == "WILD" then state.sticky[r.."_"..c] = true end
                        if state.sticky[r.."_"..c] then results[r][c] = symbols[5] end 
                    end end
                end

                local columnsWithVS = {}
                for c = 1, cols do
                    for r = 1, rows do
                        if results[r][c].isVS then columnsWithVS[c] = true; break end
                    end
                end
                
                local tempGrid = {}
                for r = 1, rows do
                    tempGrid[r] = {}
                    for c = 1, cols do
                        if columnsWithVS[c] then tempGrid[r][c] = symbols[5] else tempGrid[r][c] = results[r][c] end
                    end
                end
                
                local expandingCols = {}
                for _, line in ipairs(paylines) do
                    local firstSymbol, matchCount = nil, 0
                    for i = 1, 5 do
                        local r, c = line[i][1], line[i][2]
                        local sym = tempGrid[r][c]
                        if sym.isWild then matchCount = matchCount + 1
                        elseif firstSymbol == nil then firstSymbol = sym; matchCount = matchCount + 1
                        elseif firstSymbol.id == sym.id then matchCount = matchCount + 1
                        else break end
                    end
                    if matchCount >= 3 and (firstSymbol or symbols[5]).pays then
                        for i = 1, matchCount do
                            local c = line[i][2]
                            if columnsWithVS[c] then expandingCols[c] = true end
                        end
                    end
                end

                local activeVSCols = {}
                local vsQueue = {}
                for c = 1, cols do
                    if expandingCols[c] then
                        table.insert(vsQueue, c)
                        activeVSCols[c] = GetWinningVSMult()
                    end
                end

                local function EvaluateLinesAndFinish()
                    local totalWin, currentSegmentIdx = 0, 1
                    
                    for _, line in ipairs(paylines) do
                        local firstSymbol, matchCount, lineMult = nil, 0, 0
                        for i = 1, 5 do
                            local r, c = line[i][1], line[i][2]; local sym = results[r][c]
                            if sym.isWild then matchCount = matchCount + 1
                            elseif firstSymbol == nil then firstSymbol = sym; matchCount = matchCount + 1
                            elseif firstSymbol.id == sym.id then matchCount = matchCount + 1
                            else break end
                        end
                        
                        if matchCount >= 3 and (firstSymbol or symbols[5]).pays then
                            local usedCols = {}
                            for i = 1, matchCount do
                                local c = line[i][2]
                                if activeVSCols[c] and not usedCols[c] then lineMult = lineMult + activeVSCols[c]; usedCols[c] = true end
                            end
                            if lineMult == 0 then lineMult = 1 end
                            
                            local payout = (firstSymbol or symbols[5]).pays[matchCount - 2] * lineMult
                            if state.mode == "DEAD_PHASE2" then payout = payout * state.dmhMult end
                            totalWin = totalWin + payout
                            
                            for i = 1, matchCount - 1 do
                                local r1, c1 = line[i][1], line[i][2]; local r2, c2 = line[i+1][1], line[i+1][2]
                                local segment = GetLineSegment(currentSegmentIdx)
                                segment:SetStartPoint("CENTER", wantedSlotFrame.boxes[r1][c1]); segment:SetEndPoint("CENTER", wantedSlotFrame.boxes[r2][c2]); segment:Show()
                                currentSegmentIdx = currentSegmentIdx + 1
                            end
                            for i = 1, matchCount do wantedSlotFrame.boxes[line[i][1]][line[i][2]]:SetVertexColor(0.5, 1, 0.5) end
                        end
                    end
                    
                    local reachedMaxWin = false
                    if state.mode == "BASE" then
                        if totalWin >= MAX_WIN_LIMIT then totalWin = MAX_WIN_LIMIT; reachedMaxWin = true end
                    else
                        if state.bonusTotalWin + totalWin >= MAX_WIN_LIMIT then
                            totalWin = MAX_WIN_LIMIT - state.bonusTotalWin
                            reachedMaxWin = true
                        end
                        state.bonusTotalWin = state.bonusTotalWin + totalWin
                    end

                    if state.mode == "BASE" then
                        local sTrain, sDuel, sDead = 0, 0, 0
                        for r=1, rows do for c=1, cols do
                            if results[r][c].id == "TRAIN" then sTrain = sTrain + 1
                            elseif results[r][c].id == "DUEL" then sDuel = sDuel + 1
                            elseif results[r][c].id == "DEAD" then sDead = sDead + 1 end
                        end end

                        if sTrain >= 3 then state.mode = "TRAIN"; state.spins = 10; state.sticky = {}; state.bonusTotalWin = 0
                        elseif sDuel >= 3 then state.mode = "DUEL"; state.spins = 10; state.bonusTotalWin = 0
                        elseif sDead >= 3 then 
                            state.mode = "DEAD_PHASE1"; state.dmhLives = 3; state.dmhWilds = 0; state.dmhMult = 1; state.bonusTotalWin = 0
                            wantedSlotFrame.livesContainer:Show() 
                            UpdateLivesUI(3)
                        end
                        
                        if state.mode ~= "BASE" then
                            wantedSlotFrame.result:SetText(GC_L("LOC_3319") .. state.mode .. ")|r")
                            PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                        elseif reachedMaxWin then
                            UpdatePlayChips(totalWin); AddChipTransaction(CleanName(UnitName("player")), totalWin, "Wanted Slot")
                            wantedSlotFrame.result:SetText(GC_L("LOC_3323") .. totalWin .. GC_L("LOC_3324"))
                            PlaySound(8440)
                        elseif totalWin > 0 then
                            UpdatePlayChips(totalWin); AddChipTransaction(CleanName(UnitName("player")), totalWin, "Wanted Slot")
                            wantedSlotFrame.result:SetText(GC_L("LOC_3327") .. totalWin .. GC_L("LOC_3328"))
                        else
                            wantedSlotFrame.result:SetText(GC_L("LOC_3329"))
                        end
                    else
                        if reachedMaxWin or state.spins <= 0 then
                            if state.bonusTotalWin > 0 then
                                UpdatePlayChips(state.bonusTotalWin); AddChipTransaction(CleanName(UnitName("player")), state.bonusTotalWin, "Wanted Bonus")
                                AnnounceGameWin(GC_L("LOC_3332")..state.mode..")", state.bonusTotalWin)
                            end
                            if reachedMaxWin then
                                wantedSlotFrame.result:SetText(GC_L("LOC_3334") .. state.bonusTotalWin .. GC_L("LOC_3335"))
                                PlaySound(8440)
                            else
                                wantedSlotFrame.result:SetText(GC_L("LOC_3336") .. state.bonusTotalWin .. GC_L("LOC_3337"))
                            end
                            state.mode = "BASE"; state.spins = 0 
                        end
                    end
                    
                    wantedSlotFrame.isSpinning = false; wantedSlotFrame.spinBtn:Enable()
                    if state.mode ~= "BASE" and state.mode ~= "DEAD_PHASE1" then C_Timer.After(2.0, DoSpin) end
                end

                local function PlayNextVS(index)
                    if index > #vsQueue then
                        C_Timer.After(#vsQueue > 0 and 0.5 or 0.1, EvaluateLinesAndFinish)
                        return
                    end
                    
                    local c = vsQueue[index]
                    local vsc = wantedSlotFrame.vsCols[c]
                    vsc:Show(); vsc.tex:SetHeight(iconSize)
                    vsc.text:Show()
                    vsc.topMult:Hide(); vsc.botMult:Hide(); vsc.multText:Hide()
                    
                    local finalMult = activeVSCols[c]
                    local fakeMult = GetFakeVSMult(finalMult)
                    local winnerIsTop = math.random() > 0.5
                    
                    vsc.topMult:SetText((winnerIsTop and finalMult or fakeMult) .. "x")
                    vsc.botMult:SetText((not winnerIsTop and finalMult or fakeMult) .. "x")
                    
                    local targetHeight, curHeight = rows * spacing, iconSize
                    vsc:SetScript("OnUpdate", function(self, elapsed)
                        curHeight = curHeight + (1200 * elapsed)
                        if curHeight >= targetHeight then
                            curHeight = targetHeight; self:SetScript("OnUpdate", nil)
                            
                            PlaySoundFile(567720, "Master") 
                            vsc.text:Hide(); vsc.topMult:Show(); vsc.botMult:Show()
                            
                            C_Timer.After(1.0, function() 
                                PlaySoundFile(567722, "Master") 
                                if winnerIsTop then vsc.botMult:Hide() else vsc.topMult:Hide() end
                                
                                C_Timer.After(0.6, function()
                                    vsc.topMult:Hide(); vsc.botMult:Hide()
                                    vsc.multText:SetText(finalMult .. "x")
                                    vsc.multText:Show()
                                    PlaySound(8440)
                                    
                                    for r = 1, rows do results[r][c] = symbols[5] end
                                    C_Timer.After(0.8, function() PlayNextVS(index + 1) end)
                                end)
                            end)
                        end
                        vsc.tex:SetHeight(curHeight)
                    end)
                end
                
                PlayNextVS(1)
            end
        end
        SpinAnim()
    end
    wantedSlotFrame.spinBtn:SetScript("OnClick", DoSpin)
end
local dicePokerFrame = CreateFrame("Frame", nil, playgroundPanel.gameOverlay)
dicePokerFrame:SetAllPoints()
dicePokerFrame:Hide()

dicePokerFrame:HookScript("OnShow", function()
    if wantedSlotFrame then wantedSlotFrame:Hide() end
    if anubisFrame then anubisFrame:Hide() end
    if slotFrame then slotFrame:Hide() end
    if rouletteFrame then rouletteFrame:Hide() end
    if bjFrame then bjFrame:Hide() end
end)

do
    dicePokerFrame.title = dicePokerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    dicePokerFrame.title:SetPoint("TOP", 0, -70)
    SetCustomFont(dicePokerFrame.title, 26, "OUTLINE")
    GC_RegisterLocalizedFontString(dicePokerFrame.title, "LOC_3355")
    dicePokerFrame.title:SetTextColor(1, 0.9, 0)

    dicePokerFrame.centerStatus = dicePokerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    dicePokerFrame.centerStatus:SetPoint("CENTER", 0, 10)
    SetCustomFont(dicePokerFrame.centerStatus, 18, "OUTLINE")
    dicePokerFrame.centerStatus:SetText(GC_L("LOC_3360"))

    dicePokerFrame.aiHandText = dicePokerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    dicePokerFrame.aiHandText:SetPoint("CENTER", 0, 80)
    SetCustomFont(dicePokerFrame.aiHandText, 16, "OUTLINE")
    dicePokerFrame.aiHandText:SetTextColor(1, 0.3, 0.3)
    dicePokerFrame.aiHandText:SetText(GC_L("LOC_3365"))

    dicePokerFrame.playerHandText = dicePokerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    dicePokerFrame.playerHandText:SetPoint("CENTER", 0, -60)
    SetCustomFont(dicePokerFrame.playerHandText, 16, "OUTLINE")
    dicePokerFrame.playerHandText:SetTextColor(0.3, 0.8, 1)
    dicePokerFrame.playerHandText:SetText(GC_L("LOC_3370"))

    dicePokerFrame.btnAction = CreateLocalizedButton(dicePokerFrame, "LOC_3371", 180, 40)
    dicePokerFrame.btnAction:SetPoint("BOTTOM", 0, 40)
    dicePokerFrame.btnAction.bg:SetColorTexture(0.1, 0.6, 0.1, 0.9)

    local infoBtn = CreateLocalizedButton(dicePokerFrame, "LOC_3373", 80, 40)
    infoBtn:SetPoint("BOTTOMLEFT", dicePokerFrame, "BOTTOMLEFT", 80, 40)
    infoBtn.bg:SetColorTexture(0.2, 0.4, 0.6, 0.9)

    dicePokerFrame.betInput = CreateFrame("EditBox", nil, dicePokerFrame, "InputBoxTemplate")
    dicePokerFrame.betInput:SetSize(80, 30)
    dicePokerFrame.betInput:SetPoint("BOTTOMRIGHT", dicePokerFrame, "BOTTOMRIGHT", -80, 45)
    dicePokerFrame.betInput:SetNumeric(true)
    dicePokerFrame.betInput:SetAutoFocus(false)
    dicePokerFrame.betInput:SetText("100")
    SetCustomFont(dicePokerFrame.betInput, 14)
    
    local betLbl = dicePokerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    betLbl:SetPoint("RIGHT", dicePokerFrame.betInput, "LEFT", -10, 0)
    SetCustomFont(betLbl, 14, "OUTLINE")
    GC_RegisterLocalizedFontString(betLbl, "LOC_3386")

    dicePokerFrame.infoPanel = CreateFrame("Frame", nil, dicePokerFrame, "BackdropTemplate")
    dicePokerFrame.infoPanel:SetSize(400, 380)
    dicePokerFrame.infoPanel:SetPoint("CENTER")
    dicePokerFrame.infoPanel:SetFrameStrata("FULLSCREEN_DIALOG") 
    dicePokerFrame.infoPanel:SetFrameLevel(100)
    dicePokerFrame.infoPanel:SetBackdrop({
        bgFile="Interface\\ChatFrame\\ChatFrameBackground", edgeFile="Interface\\Tooltips\\UI-Tooltip-Border", 
        tile=true, tileSize=16, edgeSize=16, insets={left=4, right=4, top=4, bottom=4}
    })
    dicePokerFrame.infoPanel:SetBackdropColor(0.05, 0.05, 0.05, 1)
    dicePokerFrame.infoPanel:SetBackdropBorderColor(1, 0.8, 0, 1)
    dicePokerFrame.infoPanel:Hide()
    
    local closeInfoBtn = CreateFrame("Button", nil, dicePokerFrame.infoPanel, "UIPanelCloseButton")
    closeInfoBtn:SetPoint("TOPRIGHT", -5, -5)
    closeInfoBtn:SetScript("OnClick", function() dicePokerFrame.infoPanel:Hide() end)
    infoBtn:SetScript("OnClick", function() dicePokerFrame.infoPanel:Show() end)
    
    local infoText = dicePokerFrame.infoPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    infoText:SetPoint("TOPLEFT", 20, -20)
    infoText:SetWidth(360)
    infoText:SetJustifyH("LEFT")
    SetCustomFont(infoText, 13)
    infoText:SetText(
        GC_L("LOC_3402") ..
        GC_L("LOC_3403") ..
        GC_L("LOC_3404") ..
        GC_L("LOC_3405") ..
        GC_L("LOC_3406") ..
        GC_L("LOC_3407") ..
        GC_L("LOC_3408") ..
        GC_L("LOC_3409") ..
        GC_L("LOC_3410") ..
        GC_L("LOC_3411") ..
        GC_L("LOC_3412") ..
        GC_L("LOC_3413") ..
        GC_L("LOC_3414")
    )

    local function CreateDiceRow(yOffset, isPlayer)
        local row = {}
        local diceSpacing = 70
        local startX = -((5 - 1) * diceSpacing) / 2
        
        local pipPositions = {
            {1, "TOPLEFT", 12, -12}, {2, "TOPRIGHT", -12, -12}, {3, "LEFT", 12, 0},
            {4, "CENTER", 0, 0}, {5, "RIGHT", -12, 0}, {6, "BOTTOMLEFT", 12, 12}, {7, "BOTTOMRIGHT", -12, 12}
        }

        for i = 1, 5 do
            local d = CreateFrame("Button", nil, dicePokerFrame, "BackdropTemplate")
            d:SetSize(55, 55)
            d:SetPoint("CENTER", startX + (i-1)*diceSpacing, yOffset)
            d:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8", edgeFile="Interface\\Buttons\\WHITE8X8", edgeSize=2})
            d:SetBackdropColor(0.9, 0.9, 0.9, 1)
            d:SetBackdropBorderColor(0.1, 0.1, 0.1, 1)
            
            d.pips = {}
            for _, pos in ipairs(pipPositions) do
                local pip = d:CreateTexture(nil, "ARTWORK")
                pip:SetSize(12, 12)
                pip:SetPoint(pos[2], pos[3], pos[4])
                pip:SetTexture("Interface\\COMMON\\Indicator-Gray") 
                pip:SetVertexColor(0.05, 0.05, 0.15, 1) 
                pip:Hide()
                d.pips[pos[1]] = pip
            end
            
            d.SetValue = function(self, val)
                self.value = val
                for j = 1, 7 do self.pips[j]:Hide() end
                if val == 1 then self.pips[4]:Show()
                elseif val == 2 then self.pips[2]:Show(); self.pips[6]:Show()
                elseif val == 3 then self.pips[2]:Show(); self.pips[4]:Show(); self.pips[6]:Show()
                elseif val == 4 then self.pips[1]:Show(); self.pips[2]:Show(); self.pips[6]:Show(); self.pips[7]:Show()
                elseif val == 5 then self.pips[1]:Show(); self.pips[2]:Show(); self.pips[4]:Show(); self.pips[6]:Show(); self.pips[7]:Show()
                elseif val == 6 then self.pips[1]:Show(); self.pips[2]:Show(); self.pips[3]:Show(); self.pips[5]:Show(); self.pips[6]:Show(); self.pips[7]:Show()
                end
            end
            d:SetValue(6) 
            
            d.held = false
            
            d.holdText = d:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
            if isPlayer then
                d.holdText:SetPoint("TOP", d, "BOTTOM", 0, -5)
                d.holdText:SetTextColor(1, 0.8, 0)
            else
                d.holdText:SetPoint("BOTTOM", d, "TOP", 0, 5)
                d.holdText:SetTextColor(1, 0.3, 0.3)
            end
            SetCustomFont(d.holdText, 12, "OUTLINE")
            GC_RegisterLocalizedFontString(d.holdText, "LOC_MANUAL_HOLD")
            d.holdText:Hide()

            if isPlayer then
                d:SetScript("OnClick", function()
                    if dicePokerFrame.gameState == "PLAYER_TURN" then
                        d.held = not d.held
                        if d.held then
                            d:SetBackdropBorderColor(1, 0.8, 0, 1)
                            d:SetBackdropColor(0.85, 0.85, 0.7, 1)
                            d.holdText:Show()
                        else
                            d:SetBackdropBorderColor(0.1, 0.1, 0.1, 1)
                            d:SetBackdropColor(0.9, 0.9, 0.9, 1)
                            d.holdText:Hide()
                        end
                        PlaySound(856)
                    end
                end)
            end
            row[i] = d
        end
        return row
    end

    dicePokerFrame.aiDice = CreateDiceRow(140, false)
    dicePokerFrame.playerDice = CreateDiceRow(-130, true)

    local function GetPokerHand(diceArray)
        local counts = {0,0,0,0,0,0}
        for _, d in ipairs(diceArray) do counts[d.value] = counts[d.value] + 1 end
        
        local pairs, three, four, five = {}, 0, 0, 0
        for i=1, 6 do
            if counts[i] == 2 then table.insert(pairs, i) end
            if counts[i] == 3 then three = i end
            if counts[i] == 4 then four = i end
            if counts[i] == 5 then five = i end
        end
        table.sort(pairs, function(a,b) return a>b end)

        local straight = 0
        if counts[2]==1 and counts[3]==1 and counts[4]==1 and counts[5]==1 and counts[6]==1 then straight = 6
        elseif counts[1]==1 and counts[2]==1 and counts[3]==1 and counts[4]==1 and counts[5]==1 then straight = 5 end

        local winningValues = {}
        
        if five > 0 then
    winningValues[five] = true
    return 9, five, GC_L("LOC_3439"), 8, winningValues

elseif straight == 6 then
    for i=2,6 do winningValues[i] = true end
    return 8, 6, GC_L("LOC_3440"), 3, winningValues

elseif straight == 5 then
    for i=1,5 do winningValues[i] = true end
    return 7, 5, GC_L("LOC_3441"), 3, winningValues

elseif four > 0 then
    winningValues[four] = true
    return 6, four, GC_L("LOC_3442"), 4, winningValues

elseif three > 0 and #pairs == 1 then
    winningValues[three] = true
    winningValues[pairs[1]] = true
    return 5, three, "Full House", 4, winningValues

elseif three > 0 then
    winningValues[three] = true
    return 4, three, GC_L("LOC_3444"), 2, winningValues

elseif #pairs == 2 then
    winningValues[pairs[1]] = true
    winningValues[pairs[2]] = true
    return 3, pairs[1] * 10 + pairs[2], GC_L("LOC_3445"), 1.5, winningValues

elseif #pairs == 1 then
    winningValues[pairs[1]] = true
    return 2, pairs[1], GC_L("LOC_3446"), 1.5, winningValues

else
    local high = 0
    for i = 6, 1, -1 do
        if counts[i] > 0 then
            high = i
            break
        end
    end

    winningValues[high] = true
    return 1, high, GC_L("LOC_3447"), 1.5, winningValues
end
	end

    local function UpdateHandTexts()
        local aiRank, _, aiName = GetPokerHand(dicePokerFrame.aiDice)
        local pRank, _, pName = GetPokerHand(dicePokerFrame.playerDice)
        dicePokerFrame.aiHandText:SetText(GC_L("LOC_3448") .. aiName)
        dicePokerFrame.playerHandText:SetText(GC_L("LOC_MANUAL_YOU_PREFIX") .. pName)
    end

        local function AICompareHands(aRank, aTie, bRank, bTie)
        if aRank > bRank then return 1 end
        if aRank < bRank then return -1 end

        if aTie > bTie then return 1 end
        if aTie < bTie then return -1 end

        return 0
    end

    local function AIGetCounts()
        local counts = {0,0,0,0,0,0}

        for _, d in ipairs(dicePokerFrame.aiDice) do
            if d.value and d.value >= 1 and d.value <= 6 then
                counts[d.value] = counts[d.value] + 1
            end
        end

        return counts
    end

    local function AIGetStraightDraw(counts)
        local candidates = {
            {2, 3, 4, 5},
            {3, 4, 5, 6},
            {1, 2, 3, 4},
            {1, 2, 3, 4, 5},
            {2, 3, 4, 5, 6}
        }

        local bestSet = nil
        local bestCount = 0
        local bestSum = 0

        for _, seq in ipairs(candidates) do
            local keepSet = {}
            local count = 0
            local sum = 0

            for _, v in ipairs(seq) do
                if counts[v] and counts[v] > 0 then
                    keepSet[v] = true
                    count = count + 1
                    sum = sum + v
                end
            end

            if count > bestCount or (count == bestCount and sum > bestSum) then
                bestSet = keepSet
                bestCount = count
                bestSum = sum
            end
        end

        if bestCount >= 4 then
            return bestSet
        end

        return nil
    end

    local function AIApplyHoldSet(keepSet)
        for _, d in ipairs(dicePokerFrame.aiDice) do
            d.held = keepSet[d.value] == true

            if d.held then 
                d:SetBackdropBorderColor(1, 0.3, 0.3, 1) 
                d:SetBackdropColor(0.85, 0.7, 0.7, 1)
                d.holdText:Show()
            else 
                d:SetBackdropBorderColor(0.1, 0.1, 0.1, 1) 
                d:SetBackdropColor(0.9, 0.9, 0.9, 1)
                d.holdText:Hide()
            end
        end
    end

    local function AITakeDecision()
        local counts = AIGetCounts()

        local aiRank, aiTie = GetPokerHand(dicePokerFrame.aiDice)
        local playerRank, playerTie = GetPokerHand(dicePokerFrame.playerDice)

        local compareResult = AICompareHands(aiRank, aiTie, playerRank, playerTie)
        local aiIsBehind = compareResult < 0

        local keepSet = {}

        -- Öt egyforma: mindig tartja.
        if aiRank == 9 then
            for v = 1, 6 do
                if counts[v] > 0 then
                    keepSet[v] = true
                end
            end

        -- Nagy sor: mindig tartja.
        elseif aiRank == 8 then
            for v = 2, 6 do
                keepSet[v] = true
            end

        -- Kis sor: ha a játékos erősebb vagy ugyanúgy áll, megpróbálhat javítani nagy sorra.
        elseif aiRank == 7 then
            if aiIsBehind then
                keepSet[2] = true
                keepSet[3] = true
                keepSet[4] = true
                keepSet[5] = true
            else
                for v = 1, 5 do
                    keepSet[v] = true
                end
            end

        -- Négy egyforma: tartja a négyest, az ötödiket újradobja.
        elseif aiRank == 6 then
            for v = 1, 6 do
                if counts[v] == 4 then
                    keepSet[v] = true
                end
            end

        -- Full House: ha nincs lemaradva, tartja. Ha le van maradva, tartja a drillt és próbál javítani.
        elseif aiRank == 5 then
            if aiIsBehind then
                for v = 1, 6 do
                    if counts[v] == 3 then
                        keepSet[v] = true
                    end
                end
            else
                for v = 1, 6 do
                    if counts[v] > 0 then
                        keepSet[v] = true
                    end
                end
            end

        -- Drill: tartja a három egyformát.
        elseif aiRank == 4 then
            for v = 1, 6 do
                if counts[v] == 3 then
                    keepSet[v] = true
                end
            end

        -- Két pár: tartja mindkét párt, az ötödiket újradobja.
        elseif aiRank == 3 then
            for v = 1, 6 do
                if counts[v] == 2 then
                    keepSet[v] = true
                end
            end

        -- Egy pár: tartja a párt.
        elseif aiRank == 2 then
            for v = 1, 6 do
                if counts[v] == 2 then
                    keepSet[v] = true
                end
            end

        -- Magas lap: először sort próbál húzni, ha van 4-es sorhúzó.
        -- Ha nincs, akkor legalább az 5-öst és 6-ost megtartja.
        else
            local straightDraw = AIGetStraightDraw(counts)

            if straightDraw then
                keepSet = straightDraw
            else
                if counts[6] > 0 then keepSet[6] = true end
                if counts[5] > 0 then keepSet[5] = true end

                -- Ha nagyon rossz keze van, ne tartson meg semmit.
                -- Így nagyobb eséllyel javít párra vagy jobbra.
                if not keepSet[6] and not keepSet[5] then
                    keepSet = {}
                end
            end
        end

        AIApplyHoldSet(keepSet)
    end

    dicePokerFrame.gameState = "IDLE"
    local currentBet = 0

    local function ResolveGame()
        dicePokerFrame.gameState = "IDLE"
        local pRank, pTie, pName, pMult, pWinVals = GetPokerHand(dicePokerFrame.playerDice)
        local aiRank, aiTie, aiName, _, aiWinVals = GetPokerHand(dicePokerFrame.aiDice)
        
        for i=1, 5 do 
            dicePokerFrame.playerDice[i].holdText:Hide()
            dicePokerFrame.aiDice[i].holdText:Hide()
        end

        local pNameStr = CleanName(UnitName("player"))
        local playerWins = false
        local isTie = false
        
        if pRank > aiRank then playerWins = true
        elseif pRank == aiRank then
            if pTie > aiTie then playerWins = true
            elseif pTie == aiTie then isTie = true end
        end

        for i=1, 5 do
            local pd = dicePokerFrame.playerDice[i]
            local ad = dicePokerFrame.aiDice[i]
            
            if playerWins then
                if pWinVals[pd.value] then
                    pd:SetBackdropBorderColor(0, 1, 0, 1)
                    pd:SetBackdropColor(0.7, 1, 0.7, 1)
                else
                    pd:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)
                    pd:SetBackdropColor(0.5, 0.5, 0.5, 1)
                end
                ad:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)
                ad:SetBackdropColor(0.5, 0.5, 0.5, 1)
                
            elseif isTie then
                if pWinVals[pd.value] then pd:SetBackdropBorderColor(1, 1, 0, 1); pd:SetBackdropColor(1, 1, 0.7, 1)
                else pd:SetBackdropColor(0.5, 0.5, 0.5, 1) end
                
                if aiWinVals[ad.value] then ad:SetBackdropBorderColor(1, 1, 0, 1); ad:SetBackdropColor(1, 1, 0.7, 1)
                else ad:SetBackdropColor(0.5, 0.5, 0.5, 1) end
                
            else
                if aiWinVals[ad.value] then
                    ad:SetBackdropBorderColor(1, 0, 0, 1)
                    ad:SetBackdropColor(1, 0.6, 0.6, 1)
                else
                    ad:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)
                    ad:SetBackdropColor(0.5, 0.5, 0.5, 1)
                end
                pd:SetBackdropBorderColor(0.2, 0.2, 0.2, 1)
                pd:SetBackdropColor(0.5, 0.5, 0.5, 1)
            end
        end

        if playerWins then
            local winAmt = math.floor((currentBet * pMult) + 0.5)
            UpdatePlayChips(winAmt)
            AddChipTransaction(pNameStr, winAmt, GC_L("LOC_3453")..pName..")")
            dicePokerFrame.centerStatus:SetText(GC_L("LOC_3455") .. winAmt .. GC_L("LOC_3456"))
            
            if pMult >= 5 then
                PlayCasinoSound(SOUNDKIT.RAID_WARNING)
                AnnounceGameWin(GC_L("LOC_3457")..pName..")", winAmt)
            else PlaySound(1210) end
        elseif isTie then
            UpdatePlayChips(currentBet)
            dicePokerFrame.centerStatus:SetText(GC_L("LOC_3459"))
        else
            AddChipTransaction(pNameStr, -currentBet, GC_L("LOC_3460"))
            dicePokerFrame.centerStatus:SetText(GC_L("LOC_3461"))
            PlaySound(846)
        end
        
        dicePokerFrame.btnAction:SetText(GC_L("LOC_3462"))
        dicePokerFrame.btnAction:Enable()
        dicePokerFrame.betInput:Enable()
    end

    local function RollDice(isSecondRoll)
        dicePokerFrame.btnAction:Disable()
        PlayCasinoFile("Interface\\AddOns\\GuildCasino\\Sounds\\spin.mp3")
        
        local ticks = 0
        C_Timer.NewTicker(0.05, function(ticker)
            ticks = ticks + 1
            for i=1, 5 do
                if not dicePokerFrame.playerDice[i].held then dicePokerFrame.playerDice[i]:SetValue(math.random(1, 6)) end
                if not dicePokerFrame.aiDice[i].held then dicePokerFrame.aiDice[i]:SetValue(math.random(1, 6)) end
            end
            
            if ticks >= 15 then
                ticker:Cancel()
                for i=1, 5 do
                    if not dicePokerFrame.playerDice[i].held then dicePokerFrame.playerDice[i]:SetValue(math.random(1, 6)) end
                    if not dicePokerFrame.aiDice[i].held then dicePokerFrame.aiDice[i]:SetValue(math.random(1, 6)) end
                end
                
                UpdateHandTexts()
                
                if not isSecondRoll then
                    dicePokerFrame.gameState = "PLAYER_TURN"
                    AITakeDecision()
                    dicePokerFrame.centerStatus:SetText(GC_L("LOC_3465"))
                    dicePokerFrame.btnAction:SetText(GC_L("LOC_3466"))
                    dicePokerFrame.btnAction:Enable()
                else
                    ResolveGame()
                end
            end
        end)
    end

    dicePokerFrame.btnAction:SetScript("OnClick", function()
        if dicePokerFrame.gameState == "IDLE" then
            local betAmount = tonumber(dicePokerFrame.betInput:GetText()) or 0
            if betAmount <= 0 then dicePokerFrame.centerStatus:SetText(GC_L("LOC_3469")); return end
            if playChips < betAmount then dicePokerFrame.centerStatus:SetText(GC_L("LOC_3470")); return end
            
            currentBet = betAmount
            UpdatePlayChips(-currentBet)

            for i=1, 5 do
                dicePokerFrame.playerDice[i].held = false; dicePokerFrame.playerDice[i].holdText:Hide()
                dicePokerFrame.playerDice[i]:SetBackdropBorderColor(0.1,0.1,0.1,1)
                dicePokerFrame.playerDice[i]:SetBackdropColor(0.9, 0.9, 0.9, 1)
                
                dicePokerFrame.aiDice[i].held = false; dicePokerFrame.aiDice[i].holdText:Hide()
                dicePokerFrame.aiDice[i]:SetBackdropBorderColor(0.1,0.1,0.1,1)
                dicePokerFrame.aiDice[i]:SetBackdropColor(0.9, 0.9, 0.9, 1)
            end
            
            dicePokerFrame.betInput:Disable()
            dicePokerFrame.gameState = "ROLLING"
            dicePokerFrame.centerStatus:SetText(GC_L("LOC_3472"))
            dicePokerFrame.aiHandText:SetText(GC_L("LOC_3473"))
            dicePokerFrame.playerHandText:SetText(GC_L("LOC_MANUAL_YOU_EMPTY"))
            RollDice(false)
            
        elseif dicePokerFrame.gameState == "PLAYER_TURN" then
            dicePokerFrame.gameState = "ROLLING"
            dicePokerFrame.centerStatus:SetText(GC_L("LOC_3477"))
            RollDice(true)
        end
    end)
end

local function HideAllGames()
    if slotFrame then slotFrame:Hide() end
    if rouletteFrame then rouletteFrame:Hide() end
    if bjFrame then bjFrame:Hide() end
    if scratchFrame then scratchFrame:Hide() end
    if pbFrame then pbFrame:Hide() end
    if minesFrame then minesFrame:Hide() end
    if horseFrame then horseFrame:Hide() end
    if coinFrame then coinFrame:Hide() end
    if hiloFrame then hiloFrame:Hide() end
    if pokerFrame then pokerFrame:Hide() end
    if scratchBuyBtn then scratchBuyBtn:Hide() end
    if scratchResult then scratchResult:Hide() end
    if fbFrame then fbFrame:Hide() end
    if fishFrame then fishFrame:Hide() end
    if crashFrame then crashFrame:Hide() end
	if caseFrame then caseFrame:Hide() end
	if megaFrame then megaFrame:Hide() end
	if olympusFrame then olympusFrame:Hide() end
	if chickenRoadFrame then chickenRoadFrame:Hide() end
	if banditFrame then banditFrame:Hide() end
	if bookFrame then bookFrame:Hide() end
	if anubisFrame then anubisFrame:Hide() end
	if wantedSlotFrame then wantedSlotFrame:Hide() end
	if dicePokerFrame then dicePokerFrame:Hide() end
end

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_SUPER_DICE_SLOT", "Interface\\Icons\\INV_Misc_EngGizmos_17", -150, -40, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    slotFrame:Show(); slotFrame.result:SetText("")
    for i = 1, 3 do for j = 1, 3 do slotFrame.boxes[i][j]:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark") end end
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_ROULETTE", "Interface\\Icons\\INV_Misc_Dice_01", -50, -40, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    rouletteFrame:Show(); rouletteFrame.resultNum:SetText(""); rouletteFrame.resultText:SetText(GC_L("LOC_3485"))
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_BLACKJACK", "Interface\\Icons\\inv_10_inscription_darkmooncards_air_a", 50, -40, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    bjFrame:Show(); bjFrame.playerHand = {}; bjFrame.dealerHand = {}; bjFrame.UpdateCardVisuals()
    bjFrame.playerText:SetText(GC_L("LOC_3488")); bjFrame.dealerText:SetText(GC_L("LOC_3489"))
    bjFrame.hitBtn:Disable(); bjFrame.standBtn:Disable(); bjFrame.startBtn:Enable()
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3490", "Interface\\Icons\\inv_misc_notepicture1b", 150, -40, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    scratchFrame:Show(); scratchBuyBtn:Show(); scratchResult:Show()
    scratchResult:SetText(GC_L("LOC_3492"))
    for _, area in ipairs(scratchFrame.areas or {}) do 
        if area.cover then area.cover:Show(); area.coverText:Show(); area.valText:Hide(); area.scratchedBg:Hide(); area.isScratched = false end 
    end
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_PACHINKO", "Interface\\Icons\\inv_misc_discoball_01", -150, -140, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    pbFrame:Show(); pbFrame.result:SetText(""); pbFrame.ball:Hide()
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3496", "Interface\\Icons\\inv_wildfirebomb", -50, -140, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    minesFrame:Show(); minesFrame.result:SetText(GC_L("LOC_3498"))
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3499", "Interface\\Icons\\Ability_Mount_NightmareHorse", 50, -140, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    horseFrame:Show(); horseFrame.msg:SetText(GC_L("LOC_3501"))
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_COIN_FLIP", "Interface\\Icons\\INV_Misc_Coin_01", 150, -140, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    coinFrame:Show(); coinFrame.text:SetText(GC_L("LOC_3504"))
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_HILO", "Interface\\Icons\\INV_Scroll_03", -150, -240, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    hiloFrame:Show(); hiloFrame.title:SetText(GC_L("LOC_3507"))
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_TIPPMIX", "Interface\\Icons\\inv_misc_soccerball", -50, -240, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    fbFrame:Show(); if not fbFrame.isMatchActive then fbFrame.NewMatchSetup() end
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_ANGLERS_LIFE", "Interface\\Icons\\Trade_Fishing", 50, -240, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    fishFrame:Show(); fishFrame.bobber:Show(); fishFrame.lootIcon:Hide(); fishFrame.lootText:Hide()
    fishFrame.statusText:SetText(" ")
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3513", "Interface\\Icons\\inv_inscription_darkmooncard_repose_grey", 150, -240, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    pokerFrame:Show()
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_CRASH", "Interface\\Icons\\inv_zeppelinmount", -150, -340, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if crashFrame then crashFrame:Show() end
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3517", "Interface\\Icons\\INV_Box_01", -50, -340, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if caseFrame then caseFrame:Show() end
end)

CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_MEGA_BALL", "Interface\\Icons\\inv_misc_gem_pearl_04", 50, -340, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if megaFrame then megaFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_GATES_OF_VOIDSPIRE_SLOT", "Interface\\Icons\\inv12_apextalent_priest_voidshield", 150, -340, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if olympusFrame then olympusFrame:Show(); olympusFrame.ResetTable() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_CHICKEN_ROAD", "Interface\\Icons\\spell_magic_polymorphchicken", -150, -440, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if chickenRoadFrame then chickenRoadFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_LA_BANDITOS", 646059, -50, -440, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if banditFrame then banditFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_BOOK_OF_AZEROTH", "Interface\\Icons\\INV_Misc_Book_09", 50, -440, function()
    playgroundPanel.iconsFrame:Hide(); playgroundPanel.gameOverlay:Show(); HideAllGames()
    if bookFrame then bookFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_HAND_OF_ANUBISATH", 7409007, 150, -440, function()
    playgroundPanel.iconsFrame:Hide()
    playgroundPanel.gameOverlay:Show()
    HideAllGames()
    if anubisFrame then anubisFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_GAME_WANTED", "Interface\\Icons\\INV_Misc_Bandana_03", -150, -540, function()
    playgroundPanel.iconsFrame:Hide()
    playgroundPanel.gameOverlay:Show()
    HideAllGames()
    if wantedSlotFrame then wantedSlotFrame:Show() end
end)
CreateGameIcon(playgroundPanel.iconsFrame, "LOC_3531", "Interface\\Icons\\INV_Misc_Dice_02", -50, -540, function()
    playgroundPanel.iconsFrame:Hide()
    playgroundPanel.gameOverlay:Show()
    HideAllGames()
    if dicePokerFrame then dicePokerFrame:Show() end
end)






-- Guild Casino lists, sync, minimap and slash commands


GC_RefreshGameLanguage = function()
    if minesFrame and minesFrame.RefreshLanguage then minesFrame.RefreshLanguage() end
    if fishFrame and fishFrame.RefreshLanguage then fishFrame.RefreshLanguage() end
    if fbFrame and fbFrame.RefreshLanguage then fbFrame.RefreshLanguage() end
    if fbFrame and fbFrame.UpdateFormDisplays then fbFrame.UpdateFormDisplays() end
    if megaFrame and megaFrame.RefreshLanguage then megaFrame.RefreshLanguage() end
    if chickenRoadFrame and chickenRoadFrame.RefreshLanguage then chickenRoadFrame.RefreshLanguage() end
end

UpdateCasinoList = function(isTabChange)
    if playgroundPanel then playgroundPanel:Hide() end
    if scrollFrame then scrollFrame:Hide() end
    if UIFrame.resetChipsBtn then UIFrame.resetChipsBtn:Hide() end

    for i, t in ipairs(UIFrame.uiTabs) do
        if currentTab == i then
            t.bg:SetColorTexture(0.2, 0.6, 1, 0.6)
            t:GetFontString():SetTextColor(1, 1, 1)
        else
            t.bg:SetColorTexture(0.15, 0.15, 0.15, 0.9)
            t:GetFontString():SetTextColor(0.6, 0.6, 0.6)
        end
    end

    if currentTab == 1 then
        playgroundPanel:Show()

        if isTabChange then
            playgroundPanel.iconsFrame:Show()
            playgroundPanel.gameOverlay:Hide()
            if HideAllGames then HideAllGames() end
            playgroundPanel:SetAlpha(0)
            UIFrameFadeIn(playgroundPanel, 0.2, 0, 1)
        end

       
        return
    end

    scrollFrame:Show()
    if isTabChange then
        scrollFrame:SetAlpha(0)
        UIFrameFadeIn(scrollFrame, 0.2, 0, 1)
    end

    if IsPlayerAdmin() then
        UIFrame.resetChipsBtn:Show()
    end

    for _, item in pairs(listItems) do
        item:Hide()
    end

    local yOffset = -5
    local count = 1
    local myName = CleanName(UnitName("player"))

    local function GetOrCreateRow(index, isMyName)
        if not listItems[index] then
            local btn = CreateFrame("Button", nil, scrollFrame.child)
            btn:SetSize(scrollFrame:GetWidth() or 240, 20)
            btn:RegisterForClicks("AnyUp")

            btn.bg = btn:CreateTexture(nil, "BACKGROUND")
            btn.bg:SetAllPoints(btn)

            local fs = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            fs:SetPoint("LEFT", btn, "LEFT", 5, 0)
            SetCustomFont(fs, 12)
            btn:SetFontString(fs)

            btn.hl = btn:CreateTexture(nil, "HIGHLIGHT")
            btn.hl:SetAllPoints(btn)
            btn.hl:SetColorTexture(1, 1, 1, 0.1)

            listItems[index] = btn
        end

        local b = listItems[index]
        b:SetWidth(scrollFrame:GetWidth() or 240)
        b.bg:SetColorTexture(unpack(isMyName and {0.2, 0.8, 0.2, 0.25} or (index % 2 == 0 and {1, 1, 1, 0.05} or {0, 0, 0, 0})))
        return b
    end

    if currentTab == 2 then
        local sortedChips = {}

        if GuildCasino_DB_V1["CHIPS"] then
            for n, c in pairs(GuildCasino_DB_V1["CHIPS"]) do
                table.insert(sortedChips, {name = n, chips = tonumber(c) or 0})
            end
        end

        table.sort(sortedChips, function(a, b) return a.chips > b.chips end)

        if #sortedChips == 0 then
            local btn = GetOrCreateRow(count, false)
            btn:SetPoint("TOPLEFT", scrollFrame.child, "TOPLEFT", 0, yOffset)
            btn:SetText(GC_L("LOC_3851"))
            btn:SetScript("OnClick", nil)
            btn:Show()
        else
            for i, data in ipairs(sortedChips) do
                local btn = GetOrCreateRow(count, data.name == myName)
                btn:SetPoint("TOPLEFT", scrollFrame.child, "TOPLEFT", 0, yOffset)
                btn:SetText(i .. ". " .. ColorName(data.name) .. "|cFFFFFFFF: |cFF00FF00" .. data.chips .. GC_L("LOC_3856"))
                btn:SetScript("OnClick", nil)
                btn:Show()
                yOffset = yOffset - 20
                count = count + 1
            end
        end

    elseif currentTab == 3 then
        local txs = GuildCasino_DB_V1["CHIP_TRANSACTIONS"] or {}
        local txArray = {}

        for _, tx in pairs(txs) do
            table.insert(txArray, tx)
        end

        table.sort(txArray, function(a, b) return (a.id or "") > (b.id or "") end)

        if #txArray == 0 then
            local btn = GetOrCreateRow(count, false)
            btn:SetPoint("TOPLEFT", scrollFrame.child, "TOPLEFT", 0, yOffset)
            btn:SetText(GC_L("LOC_3861"))
            btn:SetScript("OnClick", nil)
            btn:Show()
        else
            for _, tx in ipairs(txArray) do
                local btn = GetOrCreateRow(count, false)
                btn:SetPoint("TOPLEFT", scrollFrame.child, "TOPLEFT", 0, yOffset)
                btn:SetText(tx.logMsg or "")
                btn:SetScript("OnClick", nil)
                btn:Show()
                yOffset = yOffset - 20
                count = count + 1
            end
        end
    end

    scrollFrame.child:SetHeight(math.abs(yOffset) + 20)
end

UIFrame.uiTabs[1]:SetScript("OnClick", function()
    if currentTab ~= 1 then
        currentTab = 1
        UpdateCasinoList(true)
    end
end)

UIFrame.uiTabs[2]:SetScript("OnClick", function()
    if currentTab ~= 2 then
        currentTab = 2
        UpdateCasinoList(true)
    end
end)

UIFrame.uiTabs[3]:SetScript("OnClick", function()
    if currentTab ~= 3 then
        currentTab = 3
        UpdateCasinoList(true)
    end
end)

local isFadingOut = false
local function ToggleUI()
    if UIFrame:IsShown() and not isFadingOut then
        isFadingOut = true
        UIFrameFadeOut(UIFrame, 0.2, UIFrame:GetAlpha(), 0)
        C_Timer.After(0.2, function()
            if isFadingOut then
                UIFrame:Hide()
                isFadingOut = false
            end
        end)
    else
        isFadingOut = false
        UpdateCasinoList(true)
        UIFrame:SetAlpha(0)
        UIFrame:Show()
        UIFrameFadeIn(UIFrame, 0.2, 0, 1)
    end
end

local minimapButton = CreateFrame("Button", "GuildCasino_MinimapButton", Minimap)
minimapButton:SetSize(32, 32)
minimapButton:SetFrameLevel(20)
minimapButton:SetToplevel(true)
minimapButton:RegisterForClicks("LeftButtonUp", "RightButtonUp")
minimapButton.icon = minimapButton:CreateTexture("GuildCasino_MinimapButtonIcon", "ARTWORK")
minimapButton.icon:SetTexture("Interface\\Icons\\INV_Misc_Dice_02")
minimapButton.icon:SetSize(20, 20)
minimapButton.icon:SetPoint("CENTER", minimapButton, "CENTER", 0, 0)
minimapButton.mask = minimapButton:CreateMaskTexture()
minimapButton.mask:SetTexture("Interface\\CharacterFrame\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
minimapButton.mask:SetAllPoints(minimapButton.icon)
minimapButton.icon:AddMaskTexture(minimapButton.mask)
minimapButton.border = minimapButton:CreateTexture(nil, "OVERLAY")
minimapButton.border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
minimapButton.border:SetSize(54, 54)
minimapButton:SetScript("OnEnter", function(self)
    local myName = CleanName(UnitName("player"))
    GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
    GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
    local chips = GuildCasino_DB_V1["CHIPS"][myName] or playChips or 0

    GameTooltip:SetOwner(self, "ANCHOR_LEFT")
    GameTooltip:SetText("|cFFFFD700Guild Casino|r")
    GameTooltip:AddLine("Your chips: |cFF00FF00" .. chips .. "|r", 1, 1, 1)
    GameTooltip:AddLine("Left click: Open casino", 0.8, 0.8, 0.8)
    GameTooltip:AddLine("Right click: Sync chips", 0.8, 0.8, 0.8)
    GameTooltip:Show()
end)

minimapButton:SetScript("OnLeave", function()
    GameTooltip:Hide()
end)
minimapButton.border:SetPoint("CENTER", minimapButton, "CENTER", 11, -11)

function minimapButton:UpdatePosition(angle)
    GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
    GuildCasino_DB_V1["minimapPos"] = angle

    local rad = math.rad(angle)
    local x = math.cos(rad) * 80
    local y = math.sin(rad) * 80

    self:ClearAllPoints()
    self:SetPoint("CENTER", Minimap, "CENTER", x, y)
end

minimapButton:SetScript("OnClick", function(self, button)
    if button == "LeftButton" then
        ToggleUI()
    elseif button == "RightButton" then
        if IsInGuild() then
            QueueAddonMessage("GUILDCASINO", "REQ_SYNC:" .. (GuildCasino_DB_V1["lastUpdate"] or "2000.01.01 00:00:00"), "GUILD")
            print("|cFF00FFFF[GuildCasino]|r: Sync requested.")
        end
    end
end)

minimapButton:SetScript("OnDragStart", function(self)
    self:SetScript("OnUpdate", function()
        local mx, my = Minimap:GetCenter()
        local px, py = GetCursorPosition()
        local scale = Minimap:GetEffectiveScale()
        px, py = px / scale, py / scale
        local angle = math.deg(math.atan2(py - my, px - mx))
        self:UpdatePosition(angle)
    end)
end)

minimapButton:SetScript("OnDragStop", function(self)
    self:SetScript("OnUpdate", nil)
end)

minimapButton:RegisterForDrag("LeftButton")

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("GUILD_ROSTER_UPDATE")
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
eventFrame:RegisterEvent("CHAT_MSG_ADDON")
eventFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        local loadedAddonName = ...
        if loadedAddonName == addonName then
            GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
            GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
            GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = GuildCasino_DB_V1["CHIP_TRANSACTIONS"] or {}
            GuildCasino_DB_V1["ChipSeason"] = GuildCasino_DB_V1["ChipSeason"] or 1
            GuildCasino_DB_V1["language"] = GuildCasino_DB_V1["language"] or "enUS"

            if playgroundPanel and playgroundPanel.muteCheck then
                playgroundPanel.muteCheck:SetChecked(GuildCasino_DB_V1["isMuted"])
            end

            SetLastUpdate(GuildCasino_DB_V1["lastUpdate"] or date("%Y.%m.%d %H:%M:%S"))
            GC_RefreshLanguageTexts()
        end

    elseif event == "PLAYER_LOGIN" then
        GuildCasino_DB_V1 = GuildCasino_DB_V1 or {}
        GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
        GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = GuildCasino_DB_V1["CHIP_TRANSACTIONS"] or {}
        GuildCasino_DB_V1["ChipSeason"] = GuildCasino_DB_V1["ChipSeason"] or 1

        UpdateClassCache()

        playChips = GetMyChips()
        if playgroundPanel and playgroundPanel.chipsDisplay then
            playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0538") .. playChips .. "|r")
        end

        if GuildCasino_DB_V1["minimapPos"] then
            minimapButton:UpdatePosition(GuildCasino_DB_V1["minimapPos"])
        else
            minimapButton:UpdatePosition(225)
        end

        if IsInGuild() then
            C_Timer.After(2, function()
                QueueAddonMessage("GUILDCASINO", "VERSION:" .. ADDON_VERSION, "GUILD")
                QueueAddonMessage("GUILDCASINO", "SET_CHIP:" .. CleanName(UnitName("player")) .. ":" .. playChips, "GUILD")
                QueueAddonMessage("GUILDCASINO", "REQ_SYNC:" .. (GuildCasino_DB_V1["lastUpdate"] or "2000.01.01 00:00:00"), "GUILD")
            end)
        end

    elseif event == "GUILD_ROSTER_UPDATE" or event == "GROUP_ROSTER_UPDATE" then
        UpdateClassCache()
        if UIFrame:IsShown() then
            UpdateCasinoList()
        end

    elseif event == "CHAT_MSG_ADDON" then
        local prefix, message, channel, sender = ...
        if prefix ~= "GUILDCASINO" or not message or CleanName(sender) == CleanName(UnitName("player")) then return end

        local firstColon = string.find(message, ":")
        local command = firstColon and string.sub(message, 1, firstColon - 1) or message
        local payload = firstColon and string.sub(message, firstColon + 1) or ""

        if command == "REQ_SYNC" then
            local myName = CleanName(UnitName("player"))
            local myChips = (GuildCasino_DB_V1["CHIPS"] and GuildCasino_DB_V1["CHIPS"][myName]) or playChips or 0

            if myChips > 0 then
                C_Timer.After(math.random() * 2, function()
                    QueueAddonMessage("GUILDCASINO", "SET_CHIP:" .. myName .. ":" .. myChips, "GUILD")
                end)
            end

            if IsPlayerAdmin() and GuildCasino_DB_V1["CHIPS"] then
                local chunk = {}
                for pName, cAmt in pairs(GuildCasino_DB_V1["CHIPS"]) do
                    table.insert(chunk, pName .. ":" .. cAmt)
                    if #chunk >= 10 then
                        QueueAddonMessage("GUILDCASINO", "SET_CHIP_BATCH:" .. table.concat(chunk, ","), "GUILD")
                        chunk = {}
                    end
                end
                if #chunk > 0 then
                    QueueAddonMessage("GUILDCASINO", "SET_CHIP_BATCH:" .. table.concat(chunk, ","), "GUILD")
                end
            end

        elseif command == "SET_CHIP" then
            local cName, cVal = strsplit(":", payload, 2)
            if cName and cVal then
                GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
                GuildCasino_DB_V1["CHIPS"][cName] = tonumber(cVal) or 0
                if UIFrame:IsShown() and currentTab == 2 then UpdateCasinoList() end
            end

        elseif command == "SET_CHIP_BATCH" then
            local pairsList = {strsplit(",", payload)}
            GuildCasino_DB_V1["CHIPS"] = GuildCasino_DB_V1["CHIPS"] or {}
            local updated = false

            for _, pairStr in ipairs(pairsList) do
                local cName, cVal = strsplit(":", pairStr)
                if cName and cVal then
                    GuildCasino_DB_V1["CHIPS"][cName] = tonumber(cVal) or 0
                    updated = true
                end
            end

            if updated and UIFrame:IsShown() and currentTab == 2 then
                UpdateCasinoList()
            end

        elseif command == "WIPE_CHIPS" then
            if not IsSenderAdmin(sender) then return end
            local newSeason = tonumber(payload) or 2

            if newSeason > (GuildCasino_DB_V1["ChipSeason"] or 1) then
                GuildCasino_DB_V1["CHIPS"] = {}
                GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = {}
                GuildCasino_DB_V1["ChipSeason"] = newSeason

                playChips = 1000
                GuildCasino_DB_V1["CHIPS"][CleanName(UnitName("player"))] = playChips

                if playgroundPanel and playgroundPanel.chipsDisplay then
                    playgroundPanel.chipsDisplay:SetText(GC_L("LOC_0538") .. playChips .. "|r")
                end

                SetLastUpdate()
                if UIFrame:IsShown() then UpdateCasinoList() end
            end

        elseif command == "CTX" then
            GuildCasino_DB_V1["CHIP_TRANSACTIONS"] = GuildCasino_DB_V1["CHIP_TRANSACTIONS"] or {}
            local id, playerName, amountStr, gameName = strsplit("|", payload)

            if id and not GuildCasino_DB_V1["CHIP_TRANSACTIONS"][id] then
                local amt = tonumber(amountStr) or 0
                local timeStr = date("%m.%d %H:%M")
                local actionText = amt > 0 and GC_L("LOC_4113") or GC_L("LOC_4114")
                local color = amt > 0 and "|cFF00FF00" or "|cFFFF0000"
                local logMsg = "["..timeStr.."] " .. (playerName or "Unknown") .. " " .. color .. actionText .. " " .. math.abs(amt) .. GC_L("LOC_4122") .. (gameName or "Casino") .. ")"

                GuildCasino_DB_V1["CHIP_TRANSACTIONS"][id] = {
                    id = id,
                    player = playerName,
                    amount = amt,
                    gameName = gameName,
                    logMsg = logMsg,
                }

                if UIFrame:IsShown() and currentTab == 3 then
                    UpdateCasinoList()
                end
            end

        elseif command == "VERSION" then
            if payload and payload ~= "" then
                if payload > ADDON_VERSION and not hasWarnedUpdate then
                    print(GC_L("LOC_4065") .. ADDON_VERSION .. ")!")
                    print(GC_L("LOC_4067") .. payload .. GC_L("LOC_4068"))
                    hasWarnedUpdate = true
                end
            end

        elseif string.sub(command, 1, 4) == "PKR_" then
            local pkrCmd = string.sub(command, 5)
            if _G.GuildCasino_PokerMsg then
                _G.GuildCasino_PokerMsg(CleanName(sender), pkrCmd, payload)
            end
        end
    end
end)

SLASH_GUILDCASINO1 = "/gc"
SLASH_GUILDCASINO2 = "/casino"
SlashCmdList["GUILDCASINO"] = function()
    ToggleUI()
end
