Cookie Clicker Ultimate Automation

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

As of 2025-12-07. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Cookie Clicker Ultimate Automation
// @name:zh-TW   餅乾點點樂全自動掛機輔助 (Cookie Clicker)
// @name:zh-CN   饼干点点乐全自动挂机辅助 (Cookie Clicker)
// @namespace    http://tampermonkey.net/
// @version      8.4.4
// @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.4:新增花園保護模式,一鍵凍結所有支出。
// @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),
            
            // v8.4.4 新增:花園保護開關
            ShowGardenProtection: GM_getValue('showGardenProtection', true),
            SpendingLocked: GM_getValue('spendingLocked', false)
        },
        // 參數
        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
            SpellCooldownSuccess: 60000,  // 施法成功冷卻時間 (毫秒)
            SpellCooldownFail: 60000,     // v8.4.3 修改:從 5000 改為 60000
            SEFailThreshold: 3,           // v8.4.3 新增:失敗 3 次觸發轉換
            SEFailResetCooldown: 300000   // v8.4.3 新增:轉換後 SE 冷卻 5 分鐘
        },
        // 記憶
        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),
            
            // v8.4.4 新增:花園保護 UI 座標與狀態記憶
            GardenProtectionX: GM_getValue('gardenProtectionX', 10),
            GardenProtectionY: GM_getValue('gardenProtectionY', 10),
            SavedSpendingStates: GM_getValue('savedSpendingStates', {
                Buy: true,
                Garden: true,
                Research: true,
                Stock: true
            })
        }
    };

    // 運行時計時器與緩存
    const Runtime = {
        Timers: {
            NextBuy: 0,
            NextRestart: 0,
            NextGarden: 0,
            NextStock: 0,
            NextSeasonCheck: 0,
            NextSpontaneousEdifice: 0  // SE 法術冷卻計時器
        },
        Stats: {
            ClickCount: 0,
            BuyUpgradeCount: 0,
            BuyBuildingCount: 0,
            SEFailCount: 0               // v8.4.3 新增:SE 失敗計數器
        },
        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.4</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:#1565c0;">
                                <input type="checkbox" id="chk-show-garden-protection" ${Config.Flags.ShowGardenProtection?'checked':''}> 🖥️ 於花園顯示保護介面
                            </label>
                            <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.4</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 bindChkWithLock = (id, key) => {
                $('#' + id).change(function() {
                    if (Config.Flags.SpendingLocked) {
                        this.checked = Config.Flags[key]; // 恢復原值
                        console.warn('⚠️ [花園保護] 支出鎖定期間無法修改此項目');
                        return false;
                    }
                    Config.Flags[key] = this.checked;
                    GM_setValue('is' + key + 'Enabled', this.checked);
                    if(key==='Click') self.updateButtonState();
                });
            };
            
            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');
            bindChkWithLock('chk-auto-buy', 'Buy');
            bindChk('chk-auto-golden', 'Golden');
            bindChkWithLock('chk-auto-garden', 'Garden');
            bindChkWithLock('chk-research', 'Research'); 
            bindChk('chk-wrinkler', 'AutoWrinkler');
            bindChkWithLock('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');
            
            // 新增花園保護開關綁定
            $('#chk-show-garden-protection').change(function() {
                Config.Flags.ShowGardenProtection = this.checked;
                GM_setValue('showGardenProtection', this.checked);
                UI.GardenProtection.updateVisibility();
            });

            $('#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(); });
        }
    };
    
    // ═══════════════════════════════════════════════════════════════
    // 花園保護模組(v8.4.4 新增)
    // ═══════════════════════════════════════════════════════════════
    UI.GardenProtection = {
        Elements: {
            Container: null
        },
        
        SavedStates: {
            Buy: null,
            Garden: null,
            Research: null,
            Stock: null
        },
        
        _cachedGardenPanel: null,
        
        create: function() {
            if (this.Elements.Container) return;
            
            const Farm = Game.Objects['Farm'];
            if (!Farm || !Farm.minigameLoaded) {
                console.warn('⚠️ [花園保護] 花園尚未解鎖,UI 創建已跳過');
                return;
            }
            
            const gardenPanel = document.getElementById('gardenPanel');
            if (!gardenPanel) return;
            
            this.Elements.Container = $(`
                <div id="garden-protection-ui" style="
                    position: absolute; 
                    left: ${Config.Memory.GardenProtectionX}px; 
                    top: ${Config.Memory.GardenProtectionY}px; 
                    width: 240px;
                    background: rgba(0, 0, 0, 0.9); 
                    color: white; 
                    border: 2px solid #ff4444;
                    border-radius: 8px; 
                    padding: 12px; 
                    z-index: 10000;
                    font-family: Arial, sans-serif;
                    box-shadow: 0 4px 20px rgba(255, 0, 0, 0.5);
                    cursor: move;
                    display: ${Config.Flags.ShowGardenProtection ? 'block' : 'none'};
                ">
                    <div style="
                        font-weight: bold; 
                        font-size: 14px; 
                        margin-bottom: 10px; 
                        text-align: center;
                        border-bottom: 1px solid #ff4444;
                        padding-bottom: 8px;
                    ">
                        🛡️ 花園保護模式
                    </div>
                    <label style="
                        display: flex; 
                        align-items: center; 
                        font-size: 13px; 
                        cursor: pointer;
                        padding: 8px;
                        background: rgba(255, 255, 255, 0.1);
                        border-radius: 4px;
                        transition: background 0.3s;
                    " onmouseover="this.style.background='rgba(255,255,255,0.2)'" 
                       onmouseout="this.style.background='rgba(255,255,255,0.1)'">
                        <input type="checkbox" id="chk-spending-lock" style="margin-right: 8px; width: 16px; height: 16px;">
                        <span style="flex: 1;">🔒 立刻停止支出</span>
                    </label>
                    <div style="
                        margin-top: 10px; 
                        font-size: 11px; 
                        color: #ffcccc; 
                        text-align: center;
                        line-height: 1.4;
                    ">
                        勾選後將鎖定:<br>
                        購買 | 花園 | 科技 | 股市
                    </div>
                </div>
            `);
            
            $(gardenPanel).append(this.Elements.Container);
            this.bindEvents();
            UI.makeDraggable(this.Elements.Container, 'gardenProtectionX', 'gardenProtectionY');
            
            console.log('✅ [花園保護] UI 已創建');
        },
        
        bindEvents: function() {
            $('#chk-spending-lock').change(function() {
                UI.GardenProtection.toggle(this.checked);
            });
        },
        
        toggle: function(enabled) {
            if (enabled) {
                // ===== 啟用停止支出 =====
                this.SavedStates.Buy = Config.Flags.Buy;
                this.SavedStates.Garden = Config.Flags.Garden;
                this.SavedStates.Research = Config.Flags.Research;
                this.SavedStates.Stock = Config.Flags.Stock;
                
                Config.Flags.Buy = false;
                Config.Flags.Garden = false;
                Config.Flags.Research = false;
                Config.Flags.Stock = false;
                
                $('#chk-auto-buy').prop('checked', false).prop('disabled', true).css('opacity', '0.5');
                $('#chk-auto-garden').prop('checked', false).prop('disabled', true).css('opacity', '0.5');
                $('#chk-research').prop('checked', false).prop('disabled', true).css('opacity', '0.5');
                $('#chk-stock').prop('checked', false).prop('disabled', true).css('opacity', '0.5');
                
                this.showLockWarning();
                
                Config.Memory.SavedSpendingStates = { ...this.SavedStates };
                GM_setValue('savedSpendingStates', Config.Memory.SavedSpendingStates);
                GM_setValue('spendingLocked', true);
                
                console.log('🔒 [花園保護] 已啟用支出鎖定');
                
            } else {
                // ===== 解除停止支出 =====
                Config.Flags.Buy = this.SavedStates.Buy !== null ? this.SavedStates.Buy : true;
                Config.Flags.Garden = this.SavedStates.Garden !== null ? this.SavedStates.Garden : true;
                Config.Flags.Research = this.SavedStates.Research !== null ? this.SavedStates.Research : true;
                Config.Flags.Stock = this.SavedStates.Stock !== null ? this.SavedStates.Stock : true;
                
                $('#chk-auto-buy').prop('checked', Config.Flags.Buy).prop('disabled', false).css('opacity', '1');
                $('#chk-auto-garden').prop('checked', Config.Flags.Garden).prop('disabled', false).css('opacity', '1');
                $('#chk-research').prop('checked', Config.Flags.Research).prop('disabled', false).css('opacity', '1');
                $('#chk-stock').prop('checked', Config.Flags.Stock).prop('disabled', false).css('opacity', '1');
                
                this.hideLockWarning();
                
                this.SavedStates = { Buy: null, Garden: null, Research: null, Stock: null };
                GM_setValue('spendingLocked', false);
                
                console.log('🔓 [花園保護] 已解除支出鎖定,功能已恢復');
            }
            
            Config.Flags.SpendingLocked = enabled;
        },
        
        showLockWarning: function() {
            const panel = $('#cookie-control-panel');
            if (panel.length && !$('#spending-lock-warning').length) {
                const warning = $(`
                    <div id="spending-lock-warning" style="
                        background: linear-gradient(135deg, #ff4444 0%, #cc0000 100%);
                        color: white;
                        padding: 12px;
                        text-align: center;
                        font-weight: bold;
                        font-size: 14px;
                        border-bottom: 2px solid rgba(255,255,255,0.3);
                        animation: pulse 2s infinite;
                    ">
                        🔒 支出已鎖定 | 花園保護模式啟用中
                    </div>
                    <style>
                        @keyframes pulse {
                            0%, 100% { opacity: 1; }
                            50% { opacity: 0.7; }
                        }
                    </style>
                `);
                panel.prepend(warning);
            }
        },
        
        hideLockWarning: function() {
            $('#spending-lock-warning').remove();
        },
        
        updateVisibility: function() {
            if (!this.Elements.Container) return;
            
            if (!this._cachedGardenPanel) {
                this._cachedGardenPanel = document.getElementById('gardenPanel');
            }
            
            if (!this._cachedGardenPanel) return;
            
            const isGardenOpen = this._cachedGardenPanel.style.display !== 'none';
            
            if (Config.Flags.ShowGardenProtection && isGardenOpen) {
                this.Elements.Container.fadeIn(200);
            } else {
                this.Elements.Container.fadeOut(200);
            }
        }
    };

    // ═══════════════════════════════════════════════════════════════
    // 2. 核心邏輯模組 (Business Logic)
    // ═══════════════════════════════════════════════════════════════
    const Logic = {
        
        Click: {
            lastRun: 0,
            
            // v8.4.2 新增:魔力充足度檢查 (含浮點容差)
            isMagicSufficient: function(current, max, threshold = 0.95, tolerance = 0.001) {
                if (max === 0) return false; // 防止除以零
                const ratio = current / max;
                return ratio >= (threshold - tolerance);
            },
            
            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();
            },
            
            // v8.4.3 核心修改:SE 施法邏輯(含失敗安全轉換)
            handleSpells: function() {
                if ((!Config.Flags.Spell && !Config.Flags.SE) || !Game.Objects['Wizard tower'].minigame) return;
                const M = Game.Objects['Wizard tower'].minigame;
                const now = Date.now();
                
                // Hand of Fate 邏輯保持不變
                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] 觸發連擊:命運之手'); 
                    }
                }
                
                // Spontaneous Edifice with Fail-Safe Conversion (v8.4.3)
                if (Config.Flags.SE && now >= Runtime.Timers.NextSpontaneousEdifice) {
                    const spell = M.spells['spontaneous edifice'];
                    const spellCost = M.getSpellCost(spell);
                    
                    if (M.magic >= spellCost && 
                        this.isMagicSufficient(M.magic, M.magicM, 0.95) && 
                        Object.keys(Game.buffs).length === 0 && 
                        document.querySelectorAll('.shimmer').length === 0) {
                        
                        const magicBefore = M.magic;
                        const castResult = M.castSpell(spell);
                        
                        if (castResult && M.magic < magicBefore) {
                            // ✅ 成功:重置計數器
                            console.log('🧙‍♂️ [AutoSpell] 閒置期:免費召喚了一座建築 (Spontaneous Edifice)');
                            Runtime.Stats.SEFailCount = 0;
                            Runtime.Timers.NextSpontaneousEdifice = now + Config.Settings.SpellCooldownSuccess;
                        } else {
                            // ❌ 失敗:計數器 +1
                            Runtime.Stats.SEFailCount++;
                            
                            if (Runtime.Stats.SEFailCount >= Config.Settings.SEFailThreshold) {
                                // 🔄 失敗達到閾值:轉換策略
                                const fthof = M.spells['hand of fate'];
                                const fthofCost = M.getSpellCost(fthof);
                                
                                if (M.magic >= fthofCost) {
                                    const fthofBefore = M.magic;
                                    const fthofResult = M.castSpell(fthof);
                                    
                                    if (fthofResult && M.magic < fthofBefore) {
                                        console.log('🔄 [AutoSpell] SE 連續失敗 ' + Config.Settings.SEFailThreshold + ' 次,已轉為施放 FtHoF');
                                        Runtime.Stats.SEFailCount = 0; // 重置計數器
                                        Runtime.Timers.NextSpontaneousEdifice = now + Config.Settings.SEFailResetCooldown;
                                    } else {
                                        console.warn('⚠️ [AutoSpell] FtHoF 施放失敗,SE 冷卻 5 分鐘');
                                        Runtime.Stats.SEFailCount = 0;
                                        Runtime.Timers.NextSpontaneousEdifice = now + Config.Settings.SEFailResetCooldown;
                                    }
                                } else {
                                    console.warn('⚠️ [AutoSpell] 魔力不足以施放 FtHoF,SE 冷卻 5 分鐘');
                                    Runtime.Stats.SEFailCount = 0;
                                    Runtime.Timers.NextSpontaneousEdifice = now + Config.Settings.SEFailResetCooldown;
                                }
                            } else {
                                // 失敗未達閾值:短冷卻
                                console.warn('⚠️ [AutoSpell] SE 施法失敗 (' + Runtime.Stats.SEFailCount + '/' + Config.Settings.SEFailThreshold + '),冷卻 60 秒');
                                Runtime.Timers.NextSpontaneousEdifice = now + Config.Settings.SpellCooldownFail;
                            }
                        }
                    }
                }
            },
            
            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;

                // ════════════════════════════════════════════
                // 1. Elder Pledge(最高優先級)
                // ════════════════════════════════════════════
                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; 
                    }
                }

                // ════════════════════════════════════════════
                // 2. Research(科技研發)
                // ════════════════════════════════════════════
                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; 
                    }
                }

                // ════════════════════════════════════════════
                // 3. Upgrades(升級)
                // ════════════════════════════════════════════
                let affordable = Game.UpgradesInStore.filter(u => u.canBuy());
                
                affordable = affordable.filter(u => {
                    if (u.id === 84) return false; // Covenant
                    if (u.id === 85) return false; // Revoke Covenant
                    if (u.id === 74) return false; // Pledge handled above
                    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; 
                }

                // ════════════════════════════════════════════
                // 4. Seed First Protocol(v8.4.3 移動到這裡)✅
                // ════════════════════════════════════════════
                if (Config.Flags.Garden) {
                    const Farm = Game.Objects['Farm'];
                    if (Farm.minigameLoaded && Farm.minigame) {
                        const M = Farm.minigame;
                        let needsSeeds = false;
                        let maxSeedPrice = 0;
                        
                        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;
                                        const seed = M.plantsById[savedId - 1];
                                        if (seed && seed.unlocked) {
                                            const price = M.getSeedPrice(seed);
                                            if (price > maxSeedPrice) maxSeedPrice = price;
                                        }
                                    }
                                }
                            }
                        }
                        // ✅ 修改:僅在資金不足時阻擋建築購買
                        if (needsSeeds && maxSeedPrice > 0) {
                            const safetyMargin = maxSeedPrice * 2;
                            if (Game.cookies < safetyMargin) {
                                if (Math.random() < 0.1) { // 降低日誌頻率
                                    console.log('[Resource] 資金凍結中:優先保留給花園種子(需要 ' + Math.round(safetyMargin) + ' 餅乾)');
                                }
                                return; 
                            }
                        }
                    }
                }

                // ════════════════════════════════════════════
                // 5. Buildings(建築)
                // ════════════════════════════════════════════
                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: {
            // ✅ v8.4.3 新增:檢查種子優先權
            checkSeedPriority: function() {
                if (!Config.Flags.Garden) return false;
                
                const Farm = Game.Objects['Farm'];
                if (!Farm.minigameLoaded || !Farm.minigame) return false;
                
                const M = Farm.minigame;
                let needsSeeds = false;
                let maxSeedPrice = 0;
                
                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;
                                const seed = M.plantsById[savedId - 1];
                                if (seed && seed.unlocked) {
                                    const price = M.getSeedPrice(seed);
                                    if (price > maxSeedPrice) maxSeedPrice = price;
                                }
                            }
                        }
                    }
                }
                
                if (needsSeeds && maxSeedPrice > 0) {
                    const safetyMargin = maxSeedPrice * 2;
                    if (Game.cookies < safetyMargin) {
                        return true; // 需要暫停股票交易
                    }
                }
                
                return false;
            },
            
            update: function(now) {
                if (!Config.Flags.Stock || now < Runtime.Timers.NextStock) return;
                const Bank = Game.Objects['Bank'];
                if (!Bank || !Bank.minigameLoaded || !Bank.minigame) return;
                
                // ✅ v8.4.3 新增:前置檢查種子需求
                if (this.checkSeedPriority()) {
                    if (Math.random() < 0.05) { // 低頻日誌
                        console.log('[Stock] 暫停交易:優先保留資金給花園種子');
                    }
                    Runtime.Timers.NextStock = now + 5000; // 5 秒後再檢查
                    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.4 (Garden Protection Update) 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();
            
            // ===== 新增:花園保護 UI 初始化 =====
            setTimeout(() => {
                UI.GardenProtection.create();
                
                // 恢復鎖定狀態(如果之前處於鎖定)
                const savedStates = GM_getValue('savedSpendingStates', null);
                if (savedStates && Config.Flags.SpendingLocked) {
                    UI.GardenProtection.SavedStates = savedStates;
                    $('#chk-spending-lock').prop('checked', true);
                    UI.GardenProtection.toggle(true);
                    console.log('🔄 [花園保護] 已恢復上次的鎖定狀態');
                }
            }, 2000);
            
            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();
                
                // ===== 新增:花園保護 UI 顯示控制 =====
                UI.GardenProtection.updateVisibility();
                
                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);
    }

})();