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-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 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.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);
    }

})();