Cookie Clicker Ultimate Automation

Automated clicker, auto-buy, auto-harvest, garden manager, stock market, season manager, Santa evolver, and Smart Sugar Lump harvester.

当前为 2025-12-05 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Cookie Clicker Ultimate Automation
// @name:zh-TW   餅乾點點樂全自動掛機輔助 (Cookie Clicker)
// @name:zh-CN   饼干点点乐全自动挂机辅助 (Cookie Clicker)
// @namespace    http://tampermonkey.net/
// @version      8.4.0
// @description  Automated clicker, auto-buy, auto-harvest, garden manager, stock market, season manager, Santa evolver, and Smart Sugar Lump harvester.
// @description:zh-TW 全功能自動掛機腳本 v8.4.0:智能糖塊收割系統 - 識別糖塊種類,保護肉色糖塊自然掉落,優化特殊糖塊收割時機。
// @author       You & AI Architect
// @match        https://wws.justnainai.com/*
// @match        https://orteil.dashnet.org/cookieclicker/*
// @icon         https://orteil.dashnet.org/cookieclicker/img/favicon.ico
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_openInTab
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ═══════════════════════════════════════════════════════════════
    // 0. 全域配置與狀態 (Configuration & State)
    // ═══════════════════════════════════════════════════════════════
    const Config = {
        // 開關狀態
        Flags: {
            Click: GM_getValue('isClickEnabled', true),
            Buy: GM_getValue('isBuyEnabled', true),
            Golden: GM_getValue('isGoldenEnabled', true), // Controls both Golden Cookies and Sugar Lumps
            Spell: GM_getValue('isSpellEnabled', true),
            Garden: GM_getValue('isGardenEnabled', true),
            Research: GM_getValue('isResearchEnabled', true),
            AutoWrinkler: GM_getValue('isAutoWrinklerEnabled', true),
            Stock: GM_getValue('isStockEnabled', true),
            SE: GM_getValue('isSEEnabled', true),
            Season: GM_getValue('isSeasonEnabled', true),
            Santa: GM_getValue('isSantaEnabled', true),
            
            GardenOverlay: GM_getValue('isGardenOverlayEnabled', true),
            GardenAvoidBuff: GM_getValue('isGardenAvoidBuff', true),
            GardenMutation: GM_getValue('isGardenMutationEnabled', false),
            
            ShowCountdown: GM_getValue('showCountdown', true),
            ShowBuffMonitor: GM_getValue('showBuffMonitor', true)
        },
        // 參數
        Settings: {
            Volume: GM_getValue('gameVolume', 50),
            ClickInterval: GM_getValue('clickInterval', 10),
            BuyStrategy: GM_getValue('buyStrategy', 'expensive'),
            BuyIntervalMs: (GM_getValue('buyIntervalHours', 0) * 3600 + GM_getValue('buyIntervalMinutes', 3) * 60 + GM_getValue('buyIntervalSeconds', 0)) * 1000,
            RestartIntervalMs: (GM_getValue('restartIntervalHours', 1) * 3600 + GM_getValue('restartIntervalMinutes', 0) * 60 + GM_getValue('restartIntervalSeconds', 0)) * 1000,
            MaxWizardTowers: 800,
            SugarLumpGoal: 100 // Threshold for Bifurcated strategy
        },
        // 記憶
        Memory: {
            SavedGardenPlot: GM_getValue('savedGardenPlot', Array(6).fill().map(() => Array(6).fill(-1))),
            PanelX: GM_getValue('panelX', window.innerWidth / 2 - 200),
            PanelY: GM_getValue('panelY', 100),
            BuffX: GM_getValue('buffX', window.innerWidth - 340),
            BuffY: GM_getValue('buffY', 150),
            CountdownX: GM_getValue('countdownX', window.innerWidth - 170),
            CountdownY: GM_getValue('countdownY', 10),
            ButtonX: GM_getValue('buttonX', 50),
            ButtonY: GM_getValue('buttonY', 50)
        }
    };

    // 運行時計時器與緩存
    const Runtime = {
        Timers: {
            NextBuy: 0,
            NextRestart: 0,
            NextGarden: 0,
            NextStock: 0,
            NextSeasonCheck: 0
        },
        Stats: {
            ClickCount: 0,
            BuyUpgradeCount: 0,
            BuyBuildingCount: 0
        },
        OriginalTitle: document.title,
        SeasonState: {
            CurrentStage: 0,
            Roadmap: [
                { name: 'Valentine', id: 'fools', target: 'BuyAllUpgrades' },
                { name: 'Christmas', id: 'christmas', target: 'MaxSanta' }
            ]
        }
    };

    // ═══════════════════════════════════════════════════════════════
    // 1. UI 與 日誌模組
    // ═══════════════════════════════════════════════════════════════
    const UI = {
        Elements: {
            Panel: null,
            FloatingBtn: null,
            Countdown: null,
            BuffMonitor: null
        },

        initStyles: function() {
            const style = document.createElement('style');
            style.type = 'text/css';
            style.innerHTML = `
                .cc-overlay-missing { border: 3px dashed #2196f3 !important; box-sizing: border-box; background: rgba(33, 150, 243, 0.1); }
                .cc-overlay-anomaly { border: 3px solid #ff4444 !important; box-shadow: inset 0 0 15px rgba(255, 0, 0, 0.6) !important; box-sizing: border-box; z-index: 10; }
                .cc-overlay-new { border: 3px solid #9c27b0 !important; box-shadow: inset 0 0 15px rgba(156, 39, 176, 0.8), 0 0 10px rgba(156, 39, 176, 0.5) !important; box-sizing: border-box; z-index: 12; }
                .cc-overlay-correct { border: 1px solid rgba(76, 175, 80, 0.4) !important; box-sizing: border-box; }
            `;
            document.head.appendChild(style);
        },

        formatMs: function(ms) {
            const s = Math.floor(ms/1000);
            return `${Math.floor(s/60)}:${s%60<10?'0':''}${s%60}`;
        },

        cleanName: function(str) {
            if (!str) return '';
            if (typeof str !== 'string') return String(str);
            return str.replace(/<[^>]*>/g, '').trim();
        },

        createFloatingButton: function() {
            if (this.Elements.FloatingBtn) return;
            this.Elements.FloatingBtn = $(`
                <div id="cookie-floating-button" style="
                    position: fixed; left: ${Config.Memory.ButtonX}px; top: ${Config.Memory.ButtonY}px; width: 50px; height: 50px;
                    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 50%;
                    display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 999999;
                    font-size: 24px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); transition: filter 0.3s;
                ">🍪</div>
            `);
            
            this.Elements.FloatingBtn.click((e) => { e.stopPropagation(); this.togglePanel(); });
            
            let isD = false;
            this.Elements.FloatingBtn.mousedown(() => isD = true);
            $(document).mousemove((e) => {
                if(isD) { 
                    Config.Memory.ButtonX = e.clientX - 25; 
                    Config.Memory.ButtonY = e.clientY - 25; 
                    this.Elements.FloatingBtn.css({left: Config.Memory.ButtonX, top: Config.Memory.ButtonY}); 
                }
            }).mouseup(() => { 
                if(isD) { 
                    isD = false; 
                    GM_setValue('buttonX', Config.Memory.ButtonX); 
                    GM_setValue('buttonY', Config.Memory.ButtonY); 
                }
            });
            $('body').append(this.Elements.FloatingBtn);
            this.updateButtonState();
        },

        updateButtonState: function() {
            if (this.Elements.FloatingBtn) {
                this.Elements.FloatingBtn.css('filter', Config.Flags.Click ? 'hue-rotate(0deg)' : 'grayscale(100%)');
            }
        },

        createControlPanel: function() {
            if (this.Elements.Panel) return;
            const generateOptions = (min, max, sel, unit) => { 
                let h=''; for(let i=min; i<=max; i++) h+=`<option value="${i}" ${i === sel?'selected':''}>${i}${unit}</option>`; return h; 
            };

            const buyMin = Math.floor(Config.Settings.BuyIntervalMs / 60000);
            const buySec = (Config.Settings.BuyIntervalMs % 60000) / 1000;
            const rstHr = Math.floor(Config.Settings.RestartIntervalMs / 3600000);
            const rstMin = (Config.Settings.RestartIntervalMs % 3600000) / 60000;

            this.Elements.Panel = $(`
                <div id="cookie-control-panel" style="
                    position: fixed; left: ${Config.Memory.PanelX}px; top: ${Config.Memory.PanelY}px; width: 420px;
                    max-height: 85vh; background: #fff; border-radius: 12px;
                    box-shadow: 0 10px 40px rgba(0,0,0,0.4); z-index: 999998;
                    font-family: Arial, sans-serif; display: none; overflow: hidden; color: #333;
                ">
                    <div id="panel-header" style="
                        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                        color: white; padding: 15px; font-weight: bold; font-size: 18px;
                        cursor: move; display: flex; justify-content: space-between; align-items: center;
                    ">
                        <span>🍪 控制面板 v8.4.0</span>
                    </div>
                    <div style="padding: 20px; overflow-y: auto; max-height: calc(85vh - 60px);">
                        
                        <div class="panel-section" style="margin-bottom:15px; padding:10px; background:#f5f7fa; border-radius:8px;">
                            <div style="font-weight:bold; color:#222; margin-bottom:10px; border-bottom:2px solid #ddd; padding-bottom:5px;">🎛️ 核心模組</div>
                            <div style="display:grid; grid-template-columns: 1fr 1fr; gap:10px; color:#333;">
                                <label><input type="checkbox" id="chk-auto-click" ${Config.Flags.Click?'checked':''}> 👉 自動點擊</label>
                                <label><input type="checkbox" id="chk-auto-buy" ${Config.Flags.Buy?'checked':''}> 🛒 自動購買</label>
                                <label><input type="checkbox" id="chk-auto-golden" ${Config.Flags.Golden?'checked':''}> ⭐ 金餅乾/糖塊</label>
                                <label><input type="checkbox" id="chk-auto-garden" ${Config.Flags.Garden?'checked':''}> 🌻 花園維護</label>
                                <label><input type="checkbox" id="chk-research" ${Config.Flags.Research?'checked':''}> 🔬 自動科技研發</label>
                                <label><input type="checkbox" id="chk-wrinkler" ${Config.Flags.AutoWrinkler?'checked':''}> 🐛 自動戳皺紋蟲</label>
                            </div>
                            <div id="lump-status" style="
                                margin-top: 10px; padding: 6px; background: rgba(0,0,0,0.05); border-radius: 4px; 
                                font-size: 12px; font-family: monospace; color: #666; border-left: 3px solid #ccc;
                            ">🍬 糖塊監控:初始化中...</div>
                        </div>

                        <div class="panel-section" style="margin-bottom:15px; padding:10px; background:#e1f5fe; border-radius:8px;">
                            <div style="font-weight:bold; color:#0277bd; margin-bottom:5px;">📈 進階掛機</div>
                            <div style="color:#333; font-size:13px; display:grid; gap:8px;">
                                <label><input type="checkbox" id="chk-stock" ${Config.Flags.Stock?'checked':''}> 股市自動交易</label>
                                <label><input type="checkbox" id="chk-se" ${Config.Flags.SE?'checked':''}> 🧙‍♂️ 閒置魔法: 憑空建築</label>
                                <label><input type="checkbox" id="chk-season" ${Config.Flags.Season?'checked':''}> 🍂 季節管理 (v8.0)</label>
                                <label><input type="checkbox" id="chk-santa" ${Config.Flags.Santa?'checked':''}> 🎅 聖誕老人進化 (v8.0)</label>
                            </div>
                        </div>

                        <div class="panel-section" style="margin-bottom:15px; padding:10px; background:#e8f5e9; border-radius:8px;">
                            <div style="font-weight:bold; color:#1b5e20; margin-bottom:5px;">🌻 花園自動化</div>
                            <label style="display:block; margin-bottom:8px; font-weight:bold; color:#2e7d32;">
                                <input type="checkbox" id="chk-garden-overlay" ${Config.Flags.GardenOverlay?'checked':''}> [x] 顯示陣型輔助網格
                            </label>
                            <label style="display:block; margin-bottom:8px; font-weight:bold; color:#d84315;">
                                <input type="checkbox" id="chk-garden-mutation" ${Config.Flags.GardenMutation?'checked':''}> 🧬 啟用自動突變管理
                            </label>
                            <label style="display:block; margin-bottom:8px; font-weight:bold; color:#1565c0;">
                                <input type="checkbox" id="chk-garden-smart" ${Config.Flags.GardenAvoidBuff?'checked':''}> 🧠 聰明補種 (Buff 期間暫停)
                            </label>
                            <button id="garden-save-btn" style="
                                width:100%; padding:8px; background:#2196f3; color:white; border:none; border-radius:4px; cursor:pointer;
                            ">💾 記憶當前陣型</button>
                        </div>

                        <div class="panel-section" style="margin-bottom:15px; padding:10px; background:#fff3e0; border-radius:8px;">
                            <div style="font-weight:bold; color:#e65100; margin-bottom:5px;">🛒 購買策略</div>
                            <select id="buy-strategy" style="width:100%; padding:5px;">
                                <option value="expensive" ${Config.Settings.BuyStrategy==='expensive'?'selected':''}>最貴優先</option>
                                <option value="cheapest" ${Config.Settings.BuyStrategy==='cheapest'?'selected':''}>最便宜優先</option>
                            </select>
                             <div style="display:flex; gap:5px; align-items:center; margin-top:5px; color:#333;">
                                <span style="font-size:13px;">間隔:</span>
                                <select id="buy-min">${generateOptions(0, 59, buyMin, '分')}</select>
                                <select id="buy-sec">${generateOptions(0, 59, buySec, '秒')}</select>
                            </div>
                        </div>

                        <div class="panel-section" style="margin-bottom:10px; padding:10px; background:#f3e5f5; border-radius:8px;">
                            <div style="font-weight:bold; color:#4a148c; margin-bottom:5px;">⚙️ 其他設定</div>
                            <label style="display:block; font-size:13px; color:#333;"><input type="checkbox" id="chk-spell" ${Config.Flags.Spell?'checked':''}> 🧙‍♂️ 基礎魔法連擊</label>
                            <label style="display:block; font-size:13px; color:#333;"><input type="checkbox" id="chk-ui-count" ${Config.Flags.ShowCountdown?'checked':''}> ⏱️ 倒數計時</label>
                            <label style="display:block; font-size:13px; color:#333;"><input type="checkbox" id="chk-ui-buff" ${Config.Flags.ShowBuffMonitor?'checked':''}> 🔥 Buff 監控</label>
                            
                            <div style="margin-top:12px; color:#333;">
                                <span style="font-size:13px; font-weight:bold;">點擊速度: <span id="spd-val">${Config.Settings.ClickInterval}</span>ms</span>
                                <input type="range" id="spd-slider" min="10" max="200" value="${Config.Settings.ClickInterval}" style="width:100%; margin-top: 8px;">
                            </div>
                             <div style="margin-top:10px; border-top:1px solid #ccc; padding-top:8px; color:#333;">
                                 <span style="font-size:13px;">自動重啟:</span>
                                 <select id="rst-hr">${generateOptions(0, 24, rstHr, '時')}</select>
                                 <select id="rst-min">${generateOptions(0, 59, rstMin, '分')}</select>
                                 <button id="btn-force-restart" style="float:right; background:#ff5252; color:white; border:none; padding:4px 10px; border-radius:4px; cursor:pointer;">立即重啟</button>
                            </div>
                        </div>
                    </div>
                </div>
            `);
            this.makeDraggable(this.Elements.Panel, 'panelX', 'panelY', '#panel-header');
            $('body').append(this.Elements.Panel);
            this.bindEvents();
        },

        togglePanel: function() {
            if (!this.Elements.Panel) this.createControlPanel();
            this.Elements.Panel.is(':visible') ? this.Elements.Panel.fadeOut(200) : this.Elements.Panel.fadeIn(200);
        },

        createCountdown: function() {
            if (this.Elements.Countdown) return;
            this.Elements.Countdown = $(`
                <div id="cookie-countdown" style="
                    position: fixed; left: ${Config.Memory.CountdownX}px; top: ${Config.Memory.CountdownY}px; padding: 8px; background: rgba(0,0,0,0.85); color: white;
                    border-radius: 8px; font-family: monospace; font-size: 12px; z-index: 999997; display: ${Config.Flags.ShowCountdown ? 'block' : 'none'};
                    width: 150px; cursor: move; border: 1px solid #444;
                ">
                    <div style="text-align: center; border-bottom: 1px solid #555; margin-bottom: 4px;">⏱️ 倒數計時 v8.4.0</div>
                    <div style="display:flex; justify-content:space-between;"><span>🔄 重啟:</span><span id="txt-rst">--:--</span></div>
                    <div style="display:flex; justify-content:space-between; margin-bottom:5px;"><span>🛒 購買:</span><span id="txt-buy">--:--</span></div>
                    <div style="border-top:1px solid #555; padding-top:5px; text-align:center;">
                        <div style="font-size:10px; margin-bottom:2px;">🔊 音量: <span id="vol-disp">${Config.Settings.Volume}</span>%</div>
                        <input type="range" id="volume-slider-mini" min="0" max="100" value="${Config.Settings.Volume}" style="width:90%;">
                    </div>
                </div>
            `);
            this.Elements.Countdown.find('#volume-slider-mini').on('input', function() {
                Config.Settings.Volume = parseInt($(this).val());
                $('#vol-disp').text(Config.Settings.Volume);
                try { if (Game.setVolume) Game.setVolume(Config.Settings.Volume); } catch(e) {}
                GM_setValue('gameVolume', Config.Settings.Volume);
            });
            this.makeDraggable(this.Elements.Countdown, 'countdownX', 'countdownY');
            $('body').append(this.Elements.Countdown);
        },

        createBuffMonitor: function() {
            if (this.Elements.BuffMonitor) return;
            this.Elements.BuffMonitor = $(`
                <div id="cookie-buff-monitor" style="
                    position: fixed; left: ${Config.Memory.BuffX}px; top: ${Config.Memory.BuffY}px; padding: 10px; background: rgba(0,0,0,0.85);
                    color: white; border-radius: 12px; font-family: 'Microsoft YaHei', sans-serif; z-index: 999996;
                    display: ${Config.Flags.ShowBuffMonitor ? 'block' : 'none'}; cursor: move; width: 320px;
                    border: 1px solid rgba(255,255,255,0.2); backdrop-filter: blur(4px);
                ">
                    <div style="font-weight: bold; margin-bottom: 10px; border-bottom: 2px solid rgba(255,255,255,0.2); padding-bottom: 8px; text-align: center; color: #ffd700;">🔥 Buff 監控</div>
                    <div id="buff-list-content" style="display: flex; flex-direction: column; gap: 8px;"></div>
                </div>
            `);
            this.makeDraggable(this.Elements.BuffMonitor, 'buffX', 'buffY');
            $('body').append(this.Elements.BuffMonitor);
        },

        updateBuffDisplay: function() {
            if (!Config.Flags.ShowBuffMonitor || !this.Elements.BuffMonitor) return;
            const buffList = $('#buff-list-content');
            buffList.empty();

            let totalCpsMult = 1;
            let totalClickMult = 1; 
            let hasBuff = false;

            if (Game.buffs) {
                for (let i in Game.buffs) {
                    hasBuff = true;
                    const buff = Game.buffs[i];
                    
                    if (buff.multCpS > 0) totalCpsMult *= buff.multCpS;
                    if (buff.multClick > 0) totalClickMult *= buff.multClick;

                    const iconUrl = 'img/icons.png';
                    const iconX = buff.icon[0] * 48;
                    const iconY = buff.icon[1] * 48;

                    const isPowerful = buff.multCpS > 50 || buff.multClick > 10;
                    const textColor = isPowerful ? '#ff4444' : 'white';
                    const bgColor = isPowerful ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.2)';

                    const buffName = UI.cleanName(buff.dname ? buff.dname : buff.name);

                    let multDisplay = '';
                    if (buff.multCpS > 0 && buff.multCpS !== 1) multDisplay = `產量 x${Math.round(buff.multCpS*10)/10}`;
                    if (buff.multClick > 0 && buff.multClick !== 1) {
                        if(multDisplay) multDisplay += ', ';
                        multDisplay += `點擊 x${Math.round(buff.multClick)}`;
                    }

                    buffList.append(`
                        <div style="display: flex; align-items: center; padding: 6px; background: ${bgColor}; border-radius: 8px; border: 1px solid rgba(255,255,255,0.05);">
                            <div style="width: 48px; height: 48px; background: url(${iconUrl}) -${iconX}px -${iconY}px; margin-right: 12px; flex-shrink: 0; border-radius:4px; box-shadow: 0 0 5px rgba(0,0,0,0.5);"></div>
                            <div>
                                <div style="font-size: 14px; font-weight: bold; color: ${textColor};">${buffName}</div>
                                <div style="font-size: 12px; color: #ffd700;">${multDisplay}</div>
                                <div style="font-size: 12px; color: #ccc;">剩餘: ${Math.ceil(buff.time / 30)}s</div>
                            </div>
                        </div>
                    `);
                }
            }
            
            if (!hasBuff) buffList.append('<div style="text-align: center; color: #666; font-size: 13px; padding: 10px;">無活性效果</div>');

            let summaryHtml = '<div style="margin-top: 8px; padding-top: 8px; border-top: 1px dashed rgba(255,255,255,0.3); text-align: right;">';
            let effectiveClickPower = totalCpsMult * totalClickMult;

            if (totalCpsMult !== 1) {
                let val = totalCpsMult < 1 ? totalCpsMult.toFixed(2) : Math.round(totalCpsMult).toLocaleString();
                summaryHtml += `<div style="color: #4caf50; font-weight: bold; font-size: 14px;">🏭 總產量: x${val}</div>`;
            }

            if (effectiveClickPower > 1) {
                let val = Math.round(effectiveClickPower).toLocaleString();
                summaryHtml += `<div style="color: #ff9800; font-weight: bold; font-size: 16px; margin-top: 2px;">⚡ 點擊倍率: x${val}</div>`;
            }

            if (typeof Game.computedMouseCps !== 'undefined') {
                let clickVal = Game.computedMouseCps;
                let formattedClick = typeof Beautify !== 'undefined' ? Beautify(clickVal) : Math.round(clickVal).toLocaleString();
                summaryHtml += `<div style="margin-top:5px; padding-top:5px; border-top:1px solid rgba(255,255,255,0.1); color:#fff; font-size:15px; font-family:monospace;">👆 點擊力: <span style="color: #ffd700;">+${formattedClick}</span></div>`;
            }

            summaryHtml += '</div>';
            buffList.append(summaryHtml);
        },

        makeDraggable: function(element, keyX, keyY, handleSelector = null) {
            let isDragging = false, startX = 0, startY = 0;
            const handle = handleSelector ? element.find(handleSelector) : element;
            handle.on('mousedown', function(e) {
                if ($(e.target).is('input, select, button')) return;
                isDragging = true; startX = e.clientX - parseInt(element.css('left')); startY = e.clientY - parseInt(element.css('top'));
            });
            $(document).on('mousemove', function(e) {
                if (isDragging) element.css({left: e.clientX - startX + 'px', top: e.clientY - startY + 'px'});
            }).on('mouseup', function() {
                if (isDragging) { isDragging = false; GM_setValue(keyX, parseInt(element.css('left'))); GM_setValue(keyY, parseInt(element.css('top'))); }
            });
        },

        bindEvents: function() {
            const self = this;
            const bindChk = (id, key) => {
                $('#'+id).change(function() {
                    Config.Flags[key] = this.checked;
                    GM_setValue('is'+key+(key.includes('Enabled')?'':'Enabled'), this.checked);
                    if(key==='Click') self.updateButtonState();
                    if(key==='ShowCountdown') self.Elements.Countdown.toggle(this.checked);
                    if(key==='ShowBuffMonitor') self.Elements.BuffMonitor.toggle(this.checked);
                    if(key==='GardenOverlay') Logic.Garden.clearOverlay();
                });
            };

            bindChk('chk-auto-click', 'Click');
            bindChk('chk-auto-buy', 'Buy');
            bindChk('chk-auto-golden', 'Golden');
            bindChk('chk-auto-garden', 'Garden');
            bindChk('chk-research', 'Research'); 
            bindChk('chk-wrinkler', 'AutoWrinkler');
            bindChk('chk-stock', 'Stock');
            bindChk('chk-se', 'SE');
            bindChk('chk-spell', 'Spell');
            bindChk('chk-ui-count', 'ShowCountdown');
            bindChk('chk-ui-buff', 'ShowBuffMonitor');
            bindChk('chk-garden-overlay', 'GardenOverlay');
            bindChk('chk-garden-mutation', 'GardenMutation');
            bindChk('chk-garden-smart', 'GardenAvoidBuff');
            bindChk('chk-season', 'Season');
            bindChk('chk-santa', 'Santa');

            $('#garden-save-btn').click(() => Logic.Garden.saveLayout());

            $('#buy-strategy').change(function() { Config.Settings.BuyStrategy = $(this).val(); GM_setValue('buyStrategy', Config.Settings.BuyStrategy); });
            $('#spd-slider').on('input', function() { Config.Settings.ClickInterval = parseInt($(this).val()); $('#spd-val').text(Config.Settings.ClickInterval); GM_setValue('clickInterval', Config.Settings.ClickInterval); });
            
            const updateBuyInt = () => {
                const min = parseInt($('#buy-min').val()); const sec = parseInt($('#buy-sec').val());
                Config.Settings.BuyIntervalMs = (min * 60 + sec) * 1000;
                GM_setValue('buyIntervalMinutes', min); GM_setValue('buyIntervalSeconds', sec);
            };
            $('#buy-min, #buy-sec').change(updateBuyInt);

            const updateRstInt = () => {
                const hr = parseInt($('#rst-hr').val()); const min = parseInt($('#rst-min').val());
                Config.Settings.RestartIntervalMs = (hr * 3600 + min * 60) * 1000;
                Core.scheduleRestart();
                GM_setValue('restartIntervalHours', hr); GM_setValue('restartIntervalMinutes', min);
            };
            $('#rst-hr, #rst-min').change(updateRstInt);

            $('#btn-force-restart').click(() => { if(confirm('確定要刷新?')) Core.performRestart(); });
        }
    };

    // ═══════════════════════════════════════════════════════════════
    // 2. 核心邏輯模組 (Business Logic)
    // ═══════════════════════════════════════════════════════════════
    const Logic = {
        
        Click: {
            lastRun: 0,
            update: function(now) {
                if (Config.Flags.Click && now - this.lastRun >= Config.Settings.ClickInterval) {
                    const bigCookie = document.querySelector('#bigCookie');
                    if (bigCookie) { bigCookie.click(); Runtime.Stats.ClickCount++; }
                    this.lastRun = now;
                }

                if (Config.Flags.Golden) {
                    // v8.4.0: Sugar Lump Logic removed from here and moved to Logic.SugarLump
                    document.querySelectorAll('#shimmers > div.shimmer').forEach(c => c.click());
                }

                this.handleSpells();
            },
            handleSpells: function() {
                if ((!Config.Flags.Spell && !Config.Flags.SE) || !Game.Objects['Wizard tower'].minigame) return;
                const M = Game.Objects['Wizard tower'].minigame;

                if (Config.Flags.Spell && M.magic >= M.getSpellCost(M.spells['hand of fate'])) {
                    let shouldCast = false;
                    for (let i in Game.buffs) {
                        if (Game.buffs[i].multCpS > 7 || Game.buffs[i].multClick > 10) { shouldCast = true; break; }
                        if (Game.buffs[i].multCpS === 7 && M.magic >= M.magicM * 0.95) { shouldCast = true; break; }
                    }
                    if (shouldCast) {
                        M.castSpell(M.spells['hand of fate']);
                        console.log('🧙‍♂️ [AutoSpell] 觸發連擊:命運之手'); 
                    }
                }
                
                if (Config.Flags.SE && M.magic >= M.getSpellCost(M.spells['spontaneous edifice'])) {
                    if (M.magic >= M.magicM * 0.95 && Object.keys(Game.buffs).length === 0 && document.querySelectorAll('.shimmer').length === 0) {
                        console.log('🧙‍♂️ [AutoSpell] 閒置期:免費召喚了一座建築 (Spontaneous Edifice)'); 
                        M.castSpell(M.spells['spontaneous edifice']);
                    }
                }
            },
            handlePrompts: function() {
                const yesButton = document.querySelector('#promptOption0');
                if (yesButton && document.querySelector('#promptContent')) {
                    const txt = document.querySelector('#promptContent').textContent;
                    if (['Warning', 'One Mind', 'revoke', '警告', '不好的结果'].some(k => txt.includes(k))) {
                        console.log('⚠️ [Safe] Auto-confirming prompt:', txt); 
                        yesButton.click();
                    }
                }
            }
        },

        // v8.4.0 New Module
        SugarLump: {
            update: function(now) {
                const statusEl = $('#lump-status');
                if (!Config.Flags.Golden) {
                    if (statusEl.length) statusEl.text('🍬 糖塊監控:已停用').css('color', '#999').css('border-left-color', '#999');
                    return;
                }
                if (typeof Game === 'undefined' || !Game.canLumps()) {
                    if (statusEl.length) statusEl.text('🍬 糖塊監控:未解鎖').css('color', '#999').css('border-left-color', '#999');
                    return;
                }

                const age = Date.now() - Game.lumpT;
                const type = Game.lumpCurrentType;
                const ripeAge = Game.lumpRipeAge;
                
                let statusText = '';
                let statusColor = '#666';
                let borderColor = '#ccc';
                let action = '';

                // Decision Matrix
                switch (type) {
                    case 3: // Meaty
                        statusText = '⛔ [肉色糖塊] 啟動保護:等待自然掉落';
                        statusColor = '#d32f2f'; // Red warning
                        borderColor = '#d32f2f';
                        action = 'SKIP';
                        break;
                    
                    case 2: // Golden
                    case 4: // Caramelized
                        if (age >= ripeAge) action = 'HARVEST_NOW';
                        else {
                            statusText = `💎 [稀有糖塊] 等待成熟 (${UI.formatMs(ripeAge - age)})`;
                            statusColor = '#e65100'; // Orange
                            borderColor = '#ffd700'; // Gold
                        }
                        break;
                    
                    case 1: // Bifurcated
                        if (age >= ripeAge) {
                            if ((Game.lumps / Config.Settings.SugarLumpGoal) > 0.9) {
                                action = 'HARVEST_NOW'; // Smart harvest
                            } else {
                                // Fallback: still harvest if ripe to ensure progress, 
                                // but logic allows for customization if needed. 
                                // For v8.4 baseline, we treat ripe as harvestable to avoid stalling.
                                action = 'HARVEST_NOW';
                            }
                        } else {
                            statusText = `🌿 [雙倍糖塊] 等待成熟 (${UI.formatMs(ripeAge - age)})`;
                            statusColor = '#2e7d32'; // Green
                            borderColor = '#4caf50';
                        }
                        break;
                    
                    default: // Normal
                        if (age >= ripeAge) action = 'HARVEST_NOW';
                        else {
                            statusText = `🍬 [普通糖塊] 等待成熟 (${UI.formatMs(ripeAge - age)})`;
                            statusColor = '#555';
                            borderColor = '#ccc';
                        }
                        break;
                }

                // Execute Action with Safety Net
                if (action === 'HARVEST_NOW') {
                    // Final Safety Net: Double Check Type
                    if (Game.lumpCurrentType !== 3) {
                        Game.clickLump();
                        console.log('🍬 [SmartLump] 自動收割糖塊 (Type: ' + type + ')');
                        statusText = '⚡ 正在收割...';
                        statusColor = '#4caf50';
                        borderColor = '#4caf50';
                    } else {
                        console.warn('⛔ [SmartLump] 攔截危險操作:試圖點擊肉色糖塊!');
                    }
                }

                if (statusEl.length) {
                    statusEl.text(statusText).css({
                        'color': statusColor,
                        'border-left-color': borderColor
                    });
                }
            }
        },

        Buy: {
            update: function(now) {
                if (!Config.Flags.Buy || now < Runtime.Timers.NextBuy) return;
                if (typeof Game === 'undefined') return;

                const pledge = Game.Upgrades['Elder Pledge'];
                if (pledge && pledge.unlocked && pledge.canBuy()) {
                    if (typeof Game.pledgeT === 'undefined' || Game.pledgeT <= 0) {
                        console.log('🛡️ [自動購買] 誓約過期,強制優先購買!');
                        pledge.buy();
                        Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs;
                        return; 
                    }
                }

                // Seed First Protocol
                if (Config.Flags.Garden) {
                    const Farm = Game.Objects['Farm'];
                    if (Farm.minigameLoaded && Farm.minigame) {
                        const M = Farm.minigame;
                        let needsSeeds = false;
                        
                        for (let y = 0; y < 6; y++) {
                            for (let x = 0; x < 6; x++) {
                                if (M.isTileUnlocked(x, y)) {
                                    const savedId = Config.Memory.SavedGardenPlot[y][x];
                                    const currentTile = M.plot[y][x];
                                    if (savedId > -1 && currentTile[0] === 0) {
                                        needsSeeds = true;
                                        break;
                                    }
                                }
                            }
                            if (needsSeeds) break;
                        }

                        if (needsSeeds) {
                            if (Math.random() < 0.1) {
                                console.log('[Resource] 資金凍結中:優先保留給花園種子');
                            }
                            return; 
                        }
                    }
                }

                if (Config.Flags.Research) {
                    const research = document.querySelectorAll('#techUpgrades .crate.upgrade.enabled');
                    if (research.length > 0) {
                        const item = research[0];
                        let resName = "未知科技";
                        const dataId = item.getAttribute('data-id');
                        if (dataId && Game.UpgradesById[dataId]) {
                            resName = Game.UpgradesById[dataId].dname || Game.UpgradesById[dataId].name;
                        } else {
                            const onMouseOver = item.getAttribute('onmouseover');
                            if (onMouseOver) {
                                 const match = /<div class="name">(.+?)<\/div>/.exec(onMouseOver);
                                 if (match) resName = match[1];
                            }
                        }
                        
                        console.log(`🔬 [自動購買] 研發科技:${UI.cleanName(resName)}`);
                        item.click(); 
                        Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs;
                        return; 
                    }
                }

                let affordable = Game.UpgradesInStore.filter(u => u.canBuy());
                
                affordable = affordable.filter(u => {
                    if (u.id === 84) return false; 
                    if (u.id === 85) return false; 
                    if (u.id === 74) return false; 

                    if (u.pool === 'toggle') {
                        const seasonSwitchIds = [182, 183, 184, 185, 209];
                        if (!seasonSwitchIds.includes(u.id)) {
                            return false; 
                        }
                    }

                    if (Config.Flags.Season) {
                        const seasonSwitchIds = [182, 183, 184, 185, 209];
                        if (seasonSwitchIds.includes(u.id)) {
                            return false; 
                        }
                    }
                    
                    return true;
                });

                if (affordable.length > 0) {
                    if (Config.Settings.BuyStrategy === 'expensive') {
                        affordable.sort((a, b) => b.getPrice() - a.getPrice());
                    } else {
                        affordable.sort((a, b) => a.getPrice() - b.getPrice());
                    }
                    
                    const target = affordable[0];
                    let upName = target.dname || target.name;
                    
                    console.log(`🛒 [自動購買-升級] : ${UI.cleanName(upName)}`);
                    target.buy();
                    Runtime.Stats.BuyUpgradeCount++;
                    Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs;
                    return; 
                }

                let affordableBuildings = [];
                for (let i in Game.ObjectsById) {
                    const obj = Game.ObjectsById[i];
                    if (obj.locked) continue;
                    if (obj.name === 'Wizard tower' && obj.amount >= Config.Settings.MaxWizardTowers) continue;
                    if (obj.price <= Game.cookies) {
                        affordableBuildings.push(obj);
                    }
                }

                if (affordableBuildings.length > 0) {
                    if (Config.Settings.BuyStrategy === 'expensive') {
                        affordableBuildings.sort((a, b) => b.price - a.price);
                    } else {
                        affordableBuildings.sort((a, b) => a.price - b.price);
                    }
                    
                    const targetB = affordableBuildings[0];
                    let buildName = targetB.displayName || targetB.name; 
                    const domElement = document.getElementById('productName' + targetB.id);
                    if (domElement) {
                        buildName = domElement.innerText; 
                    }
                    
                    console.log(`🛒 [自動購買-建築] : ${UI.cleanName(buildName)}`);
                    targetB.buy(1);
                    Runtime.Stats.BuyBuildingCount++;
                    Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs;
                }
            }
        },

        Wrinkler: {
            hasLoggedShiny: false,
            update: function(now) {
                if (!Config.Flags.AutoWrinkler) return;
                if (typeof Game === 'undefined' || !Game.wrinklers) return;

                let currentShinyPresent = false;

                for (let i in Game.wrinklers) {
                    let w = Game.wrinklers[i];
                    if (w.phase > 0 && w.close === 1) {
                        if (w.type === 1) {
                            currentShinyPresent = true;
                            if (!this.hasLoggedShiny) {
                                console.log('%c✨ [Wrinkler] 發現閃光皺紋蟲!已啟動保護機制!', 'color: #ffd700; font-weight: bold; background: #333; padding: 4px;');
                                this.hasLoggedShiny = true;
                            }
                        } else {
                            w.hp = 0; 
                        }
                    }
                }

                if (!currentShinyPresent) {
                    this.hasLoggedShiny = false;
                }
            }
        },

        Garden: {
            update: function(now) {
                if (!Config.Flags.Garden || now < Runtime.Timers.NextGarden) return;
                if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigameLoaded) return;
                
                const M = Game.Objects['Farm'].minigame;
                if (!M) return;

                let isCpsBuffActive = false;
                if (Config.Flags.GardenAvoidBuff) {
                    for (let i in Game.buffs) {
                        if (Game.buffs[i].multCpS > 1) { isCpsBuffActive = true; break; }
                    }
                }

                for (let y = 0; y < 6; y++) {
                    for (let x = 0; x < 6; x++) {
                        if (!M.isTileUnlocked(x, y)) continue;

                        const tile = M.plot[y][x];
                        const tileId = tile[0];
                        const tileAge = tile[1];
                        const savedId = Config.Memory.SavedGardenPlot[y][x];

                        if (tileId > 0) {
                            const plant = M.plantsById[tileId - 1];
                            const isAnomaly = (savedId !== -1 && tileId !== savedId) || (savedId === -1);
                            const plantName = UI.cleanName(plant.name);

                            if (!isAnomaly) {
                                if (tileAge >= 98 && tileAge >= plant.mature) M.harvest(x, y); 
                                continue; 
                            }

                            if (Config.Flags.GardenMutation) {
                                if (plant.unlocked) {
                                    M.harvest(x, y);
                                    console.log(`🧹 [花園] 鏟除雜物/已知變異 (紅框): ${plantName}`);
                                } else {
                                    if (tileAge >= plant.mature) {
                                        M.harvest(x, y);
                                        console.log(`🎉 [花園] 成功收割新品種種子 (紫框): ${plantName}`);
                                    }
                                }
                            } else {
                                if (plant.weed) M.harvest(x, y);
                            }
                            continue;
                        }

                        if (tileId === 0) {
                            if (savedId !== -1 && savedId !== null) {
                                const seed = M.plantsById[savedId - 1];
                                if (seed && seed.unlocked && M.canPlant(seed)) {
                                    if (Config.Flags.GardenAvoidBuff && isCpsBuffActive) continue;
                                    M.useTool(seed.id, x, y);
                                }
                            }
                        }
                    }
                }
                Runtime.Timers.NextGarden = now + 2500;
            },
            updateOverlay: function() {
                if (!Config.Flags.GardenOverlay) return;
                if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigameLoaded) return;
                const M = Game.Objects['Farm'].minigame;
                if (!M) return;

                for (let y = 0; y < 6; y++) {
                    for (let x = 0; x < 6; x++) {
                        const tileDiv = document.getElementById(`gardenTile-${x}-${y}`);
                        if (!tileDiv) continue;
                        tileDiv.classList.remove('cc-overlay-missing', 'cc-overlay-anomaly', 'cc-overlay-correct', 'cc-overlay-new');
                        if (!M.isTileUnlocked(x, y)) continue;

                        const savedId = Config.Memory.SavedGardenPlot[y][x];
                        const realId = M.plot[y][x][0];

                        if (realId === 0 && savedId !== -1) {
                            tileDiv.classList.add('cc-overlay-missing');
                        } else if (realId !== 0) {
                            const plant = M.plantsById[realId - 1];
                            const isAnomaly = (savedId !== -1 && realId !== savedId) || (savedId === -1);
                            if (isAnomaly) {
                                if (plant.unlocked) tileDiv.classList.add('cc-overlay-anomaly');
                                else tileDiv.classList.add('cc-overlay-new');
                            } else if (realId === savedId) {
                                tileDiv.classList.add('cc-overlay-correct');
                            }
                        }
                    }
                }
            },
            clearOverlay: function() {
                $('.cc-overlay-missing, .cc-overlay-anomaly, .cc-overlay-correct, .cc-overlay-new').removeClass('cc-overlay-missing cc-overlay-anomaly cc-overlay-correct cc-overlay-new');
            },
            saveLayout: function() {
                if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigame) { alert('花園未就緒!'); return; }
                const M = Game.Objects['Farm'].minigame;
                let newLayout = [];
                for (let y = 0; y < 6; y++) {
                    let row = [];
                    for (let x = 0; x < 6; x++) {
                        if (M.isTileUnlocked(x, y)) {
                            const tile = M.plot[y][x];
                            row.push(tile[0] === 0 ? -1 : tile[0]);
                        } else {
                            row.push(-1);
                        }
                    }
                    newLayout.push(row);
                }
                Config.Memory.SavedGardenPlot = newLayout;
                GM_setValue('savedGardenPlot', Config.Memory.SavedGardenPlot);
                const btn = $('#garden-save-btn');
                const originalText = btn.text();
                btn.text('✅ 已儲存!').css('background', '#4caf50');
                setTimeout(() => btn.text(originalText).css('background', '#2196f3'), 1500);
            }
        },

        Stock: {
            update: function(now) {
                if (!Config.Flags.Stock || now < Runtime.Timers.NextStock) return;
                const Bank = Game.Objects['Bank'];
                if (!Bank || !Bank.minigameLoaded || !Bank.minigame) return;
                const M = Bank.minigame;

                for (let i = 0; i < M.goodsById.length; i++) {
                    const good = M.goodsById[i];
                    const price = M.getGoodPrice(good);
                    const rv = M.getRestingVal(good.id);
                    const goodName = UI.cleanName(good.name);
                    
                    if (price < rv * 0.5) {
                        const maxStock = M.getGoodMaxStock(good);
                        if (good.stock < maxStock && Game.cookies > price) {
                            M.buyGood(good.id, 10000);
                        }
                    }
                    if (price > rv * 1.5) {
                        if (good.stock > 0) {
                            M.sellGood(good.id, 10000);
                            console.log(`📉 [股市] 獲利賣出 ${goodName} @ $${price.toFixed(2)} (RV: ${rv.toFixed(2)})`);
                        }
                    }
                }
                Runtime.Timers.NextStock = now + 3000;
            }
        },

        Season: {
            update: function(now) {
                if (!Config.Flags.Season || now < Runtime.Timers.NextSeasonCheck) return;
                
                const currentStage = Runtime.SeasonState.Roadmap[Runtime.SeasonState.CurrentStage];
                if (!currentStage) return;

                const currentSeason = Game.season;
                const targetSeasonId = currentStage.id;

                if (currentSeason !== targetSeasonId) {
                    const switcher = Object.values(Game.Upgrades).find(u => u.toggle && u.season === targetSeasonId);
                    if (switcher) {
                        if (!switcher.bought && switcher.canBuy()) {
                            console.log(`🍂 [Season] 切換季節至: ${currentStage.name}`);
                            switcher.buy();
                        }
                    }
                    Runtime.Timers.NextSeasonCheck = now + 2000;
                    return;
                }

                let isComplete = false;
                if (currentStage.target === 'BuyAllUpgrades') {
                    const remaining = Object.values(Game.Upgrades).filter(u => u.season === targetSeasonId && !u.bought && u.unlocked);
                    if (remaining.length === 0) isComplete = true;
                    else {
                        remaining.forEach(u => { if (u.canBuy()) { u.buy(); console.log(`🍂 [Season] 購買季節餅乾: ${u.name}`); } });
                    }
                } else if (currentStage.target === 'MaxSanta') {
                    if (Game.santaLevel >= 14) { 
                        const remaining = Object.values(Game.Upgrades).filter(u => u.season === targetSeasonId && !u.bought && u.unlocked);
                        if (remaining.length === 0) isComplete = true;
                    }
                }

                if (isComplete) {
                    console.log(`🍂 [Season] 階段完成: ${currentStage.name}`);
                    Runtime.SeasonState.CurrentStage++;
                }

                Runtime.Timers.NextSeasonCheck = now + 5000;
            }
        },

        Santa: {
            update: function(now) {
                if (!Config.Flags.Santa || Game.season !== 'christmas') return;
                
                if (Game.Has('A festive hat') && !Game.Has('Santa Claus')) {
                }

                if (Game.santaLevel < 14) { 
                    if (typeof Game.UpgradeSanta === 'function') {
                        Game.UpgradeSanta(); 
                    }
                }
            }
        },

        updateTitle: function() {
            if (typeof Game === 'undefined') return;
            let totalMult = 1;
            let isWorthClicking = false;
            if (Game.buffs) {
                for (let i in Game.buffs) {
                    const buff = Game.buffs[i];
                    if (buff.multCpS > 0) totalMult *= buff.multCpS;
                    if (buff.multClick > 0) totalMult *= buff.multClick;
                    if (buff.multClick > 1 || buff.multCpS > 7) isWorthClicking = true;
                }
            }
            let coords = "0,0";
            const bigCookie = document.querySelector('#bigCookie');
            if (bigCookie) {
                const rect = bigCookie.getBoundingClientRect();
                coords = `${Math.round(rect.left + rect.width / 2)},${Math.round(rect.top + rect.height / 2)}`;
            }
            const signal = isWorthClicking ? "⚡ATTACK" : "💤IDLE";
            const displayMult = totalMult > 1000 ? (totalMult/1000).toFixed(1) + 'k' : Math.round(totalMult);
            document.title = `[${signal}|${displayMult}x|${coords}] ${Runtime.OriginalTitle}`;
        }
    };

    // ═══════════════════════════════════════════════════════════════
    // 3. 系統核心 (System Core)
    // ═══════════════════════════════════════════════════════════════
    const Core = {
        init: function() {
            console.log('🍪 Cookie Clicker Ultimate v8.4.0 (Smart Sugar Lump) Loaded');
            
            const scriptRestarted = localStorage.getItem('cookieScriptRestarted');
            if (scriptRestarted) {
                console.log('🔄 Script restarted automatically.');
                localStorage.removeItem('cookieScriptRestarted');
            }

            UI.initStyles();
            UI.createFloatingButton();
            UI.createControlPanel();
            UI.createCountdown();
            UI.createBuffMonitor();
            
            try { if (Game.setVolume) Game.setVolume(Config.Settings.Volume); } catch(e) {}

            this.scheduleRestart();
            this.startHeartbeat();
            
            setTimeout(() => {
                Logic.Garden.clearOverlay();
                UI.updateButtonState();
            }, 3000);

            document.addEventListener('keydown', function(e) {
                if (e.key === 'F8') {
                    e.preventDefault();
                    Config.Flags.Click = !Config.Flags.Click;
                    GM_setValue('isClickEnabled', Config.Flags.Click);
                    UI.updateButtonState();
                    if(UI.Elements.Panel) $('#chk-auto-click').prop('checked', Config.Flags.Click);
                }
            });
        },

        startHeartbeat: function() {
            const self = this;
            
            const fastLoop = () => {
                const now = Date.now();
                Logic.Click.update(now);
                const nextDelay = Config.Flags.Click ? Math.max(10, Config.Settings.ClickInterval) : 1000;
                setTimeout(fastLoop, nextDelay); 
            };
            fastLoop();

            setInterval(() => {
                const now = Date.now();
                Logic.Buy.update(now);
                Logic.Garden.update(now);
                Logic.Garden.updateOverlay();
                Logic.SugarLump.update(now); // v8.4.0: Added Smart Sugar Lump logic
                Logic.Wrinkler.update(now);
                Logic.Stock.update(now);
                Logic.Season.update(now);
                Logic.Santa.update(now);
                Logic.updateTitle();
                Logic.Click.handlePrompts(); 
                
                UI.updateBuffDisplay();
                
                if (Config.Flags.ShowCountdown) {
                    $('#txt-rst').text(UI.formatMs(Math.max(0, Runtime.Timers.NextRestart - now)));
                    $('#txt-buy').text(Config.Flags.Buy ? UI.formatMs(Math.max(0, Runtime.Timers.NextBuy - now)) : '--:--');
                }
            }, 1000);
        },

        scheduleRestart: function() {
            if (Runtime.Timers.RestartInterval) clearInterval(Runtime.Timers.RestartInterval);
            let interval = Config.Settings.RestartIntervalMs;
            if (interval < 60000) interval = 60000;
            Runtime.Timers.NextRestart = Date.now() + interval;
            
            if(this.restartTimer) clearTimeout(this.restartTimer);
            this.restartTimer = setTimeout(() => this.performRestart(), interval);
        },

        performRestart: function() {
            if (Game.WriteSave) Game.WriteSave();
            localStorage.setItem('cookieScriptRestarted', 'true');
            setTimeout(() => { 
                GM_openInTab(window.location.href, { active: true, insert: true, setParent: false }); 
                setTimeout(() => window.close(), 1000); 
            }, 500);
        }
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => setTimeout(() => Core.init(), 1500));
    } else {
        setTimeout(() => Core.init(), 1500);
    }

})();