Cookie Clicker Ultimate Automation

Automated clicker, auto-buy, auto-harvest, garden manager (Auto Mutation), stock market trader, and HUD overlay.

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

您需要先安装一款用户脚本管理器扩展,例如 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      7.4.3
// @description  Automated clicker, auto-buy, auto-harvest, garden manager (Auto Mutation), stock market trader, and HUD overlay.
// @description:zh-TW 全功能自動掛機腳本:v7.4.3 完美修復版 - 包含花園突變管理,並完整還原所有模組(購買/股市/魔法/彈窗)的日誌顯示。
// @description:zh-CN 全功能自动挂机脚本:v7.4.3 完美修复版 - 包含花园突变管理,并完整还原所有模组(购买/股市/魔法/弹窗)的日志显示。
// @author       You
// @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';

    // ═══════════════════════════════════════════════════════════════
    // 1. 核心變量 & 狀態記憶
    // ═══════════════════════════════════════════════════════════════
    let isClickEnabled = GM_getValue('isClickEnabled', false);
    let isBuyEnabled = GM_getValue('isBuyEnabled', false);
    let isGoldenEnabled = GM_getValue('isGoldenEnabled', false);
    let isSpellEnabled = GM_getValue('isSpellEnabled', true);
    let isGardenEnabled = GM_getValue('isGardenEnabled', false);
    let isResearchEnabled = GM_getValue('isResearchEnabled', true);
    let isStockEnabled = GM_getValue('isStockEnabled', false);
    let isSEEnabled = GM_getValue('isSEEnabled', false);
    
    // v7.1 ~ v7.4 花園相關設定
    let isGardenOverlayEnabled = GM_getValue('isGardenOverlayEnabled', false);
    let isGardenAvoidBuff = GM_getValue('isGardenAvoidBuff', true);
    let isGardenMutationEnabled = GM_getValue('isGardenMutationEnabled', false);

    // 統計計數
    let clickCount = 0;
    let buyUpgradeCount = 0;
    let buyBuildingCount = 0;
    let goldenCookieCount = 0;

    // Interval IDs
    let intervalId = null;
    let buyIntervalId = null;
    let goldenCheckIntervalId = null;
    let gardenIntervalId = null;
    let stockIntervalId = null;
    let restartIntervalId = null;
    let countdownIntervalId = null;
    let promptCheckIntervalId = null;
    let buffCheckIntervalId = null;
    let ahkSignalIntervalId = null;
    let overlayIntervalId = null;

    // 時間控制
    let nextRestartTime = 0;
    let nextBuyTime = 0;

    // 設定參數
    let gameVolume = GM_getValue('gameVolume', 50);
    let clickInterval = GM_getValue('clickInterval', 50);
    let buyStrategy = GM_getValue('buyStrategy', 'expensive');
    
    let buyIntervalHours = GM_getValue('buyIntervalHours', 0);
    let buyIntervalMinutes = GM_getValue('buyIntervalMinutes', 3);
    let buyIntervalSeconds = GM_getValue('buyIntervalSeconds', 0);

    let restartIntervalHours = GM_getValue('restartIntervalHours', 1);
    let restartIntervalMinutes = GM_getValue('restartIntervalMinutes', 0);
    let restartIntervalSeconds = GM_getValue('restartIntervalSeconds', 0);

    const MAX_WIZARD_TOWERS = 800;
    
    // 花園陣型記憶
    let savedGardenPlot = GM_getValue('savedGardenPlot', Array(6).fill().map(() => Array(6).fill(-1)));

    // UI 位置
    let showCountdown = GM_getValue('showCountdown', true);
    let showBuffMonitor = GM_getValue('showBuffMonitor', true);
    let countdownX = GM_getValue('countdownX', window.innerWidth - 170);
    let countdownY = GM_getValue('countdownY', 10);
    let buffX = GM_getValue('buffX', window.innerWidth - 340);
    let buffY = GM_getValue('buffY', 150);
    let currentX = GM_getValue('buttonX', 50);
    let currentY = GM_getValue('buttonY', 50);

    // DOM 元素引用
    let countdownDisplay = null;
    let buffDisplay = null;
    let controlPanel = null;
    let floatingButton = null;

    const targetSelector = '#bigCookie';
    let originalTitle = document.title;

    // ═══════════════════════════════════════════════════════════════
    // 2. 初始化流程
    // ═══════════════════════════════════════════════════════════════
    function init() {
        console.log('🍪 Cookie Clicker Ultimate Automation v7.4.3 Loaded (All Logs & Mutation)');

        const scriptRestarted = localStorage.getItem('cookieScriptRestarted');
        if (scriptRestarted) {
            console.log('🔄 Script restarted automatically.');
            localStorage.removeItem('cookieScriptRestarted');
        }

        if (currentX < 0 || currentX > window.innerWidth) currentX = 50;
        
        injectCustomStyles();
        createFloatingButton();
        createControlPanel();
        createCountdownDisplay();
        createBuffDisplay();
        setGameVolume(gameVolume);

        goldenCheckIntervalId = setInterval(checkGoldenCookie, 1000);
        promptCheckIntervalId = setInterval(autoConfirmPrompt, 1000);
        buffCheckIntervalId = setInterval(updateBuffDisplay, 500);
        ahkSignalIntervalId = setInterval(updateTitleForAHK, 1000);
        gardenIntervalId = setInterval(autoGarden, 2500);
        stockIntervalId = setInterval(autoStock, 3000);
        overlayIntervalId = setInterval(updateGardenOverlay, 1000);

        startCountdown();
        scheduleAutoRestart();

        setTimeout(() => {
            if (isClickEnabled) startAutoClick();
            if (isBuyEnabled) startAutoBuy();
            updateAllDisplays();
        }, 2000);

        document.addEventListener('keydown', function(e) {
            if (e.key === 'F8') {
                e.preventDefault();
                toggleAutoClick();
            }
        });
    }

    function injectCustomStyles() {
        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);
    }

    // ═══════════════════════════════════════════════════════════════
    // 3. 核心功能模組
    // ═══════════════════════════════════════════════════════════════

    // --- 花園模組 ---
    function autoGarden() {
        if (!isGardenEnabled) return;
        if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigameLoaded) return;
        
        const M = Game.Objects['Farm'].minigame;
        if (!M) return;

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

        let skippedLogPrinted = false;

        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 = savedGardenPlot[y][x];

                // 1. 處理已種植的格子
                if (tileId > 0) {
                    const plant = M.plantsById[tileId - 1];
                    const isAnomaly = (savedId !== -1 && tileId !== savedId) || (savedId === -1);

                    // Case A: 符合預期
                    if (!isAnomaly) {
                        if (tileAge >= 98 && tileAge >= plant.mature) {
                            M.harvest(x, y); 
                        }
                        continue; 
                    }

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

                // 2. 自動補種
                if (tileId === 0) {
                    if (savedId !== -1 && savedId !== null) {
                        const seed = M.plantsById[savedId - 1];
                        if (seed && seed.unlocked && M.canPlant(seed)) {
                            if (isGardenAvoidBuff && isCpsBuffActive) {
                                if (!skippedLogPrinted) {
                                    console.log('🌻 [花園] 檢測到產量 Buff,暫停補種。');
                                    skippedLogPrinted = true;
                                }
                                continue;
                            }
                            M.useTool(seed.id, x, y);
                        }
                    }
                }
            }
        }
    }

    // --- 視覺覆蓋層 ---
    function updateGardenOverlay() {
        if (!isGardenOverlayEnabled) 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 = 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');
                    }
                }
            }
        }
    }

    function saveGardenLayout() {
        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);
        }
        savedGardenPlot = newLayout;
        GM_setValue('savedGardenPlot', savedGardenPlot);
        const btn = $('#garden-save-btn');
        const originalText = btn.text();
        btn.text('✅ 已儲存!').css('background', '#4caf50');
        setTimeout(() => btn.text(originalText).css('background', '#2196f3'), 1500);
    }

    // --- 購買與點擊模組 ---
    function updateTitleForAHK() {
        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}] ${originalTitle}`;
    }

    function autoClick() {
        const element = document.querySelector(targetSelector);
        if (element) { element.click(); clickCount++; }
    }
    function startAutoClick() {
        if (intervalId) clearInterval(intervalId);
        intervalId = setInterval(autoClick, clickInterval);
        isClickEnabled = true; updateAllDisplays();
    }
    function stopAutoClick() { if (intervalId) clearInterval(intervalId); isClickEnabled = false; updateAllDisplays(); }
    function toggleAutoClick() { isClickEnabled = !isClickEnabled; GM_setValue('isClickEnabled', isClickEnabled); isClickEnabled ? startAutoClick() : stopAutoClick(); }

    function autoBuy() {
        if (typeof Game === 'undefined') return;
        if (Game.Upgrades['Elder Pledge'] && Game.Upgrades['Elder Pledge'].unlocked && Game.Upgrades['Elder Pledge'].bought === 0 && Game.Upgrades['Elder Pledge'].canBuy()) {
            console.log('🛡️ [AutoBuy] 誓約過期,強制後台購買!');
            Game.Upgrades['Elder Pledge'].buy(); nextBuyTime = Date.now() + getBuyInterval(); return;
        }
        if (isResearchEnabled) {
            const research = document.querySelectorAll('#techUpgrades .crate.upgrade.enabled');
            if (research.length > 0) { 
                const item = research[0];
                console.log(`🛒 [購買-科技] 研究: ${getUpgradeName(item)}`);
                item.click(); 
                nextBuyTime = Date.now() + getBuyInterval(); 
                return; 
            }
        }
        const upgradesList = document.querySelectorAll('#upgrades .crate.upgrade.enabled');
        if (upgradesList.length > 0) {
            const selected = selectByStrategy(upgradesList, true);
            if (selected) { 
                console.log(`🛒 [購買-升級] 購買: ${getUpgradeName(selected)}`);
                selected.click(); 
                buyUpgradeCount++; 
                nextBuyTime = Date.now() + getBuyInterval(); 
                return; 
            }
        }
        const buildings = document.querySelectorAll('.product.unlocked.enabled');
        if (buildings.length > 0) {
            const selected = selectByStrategy(buildings, false);
            if (selected) { 
                const buildId = selected.id.replace('product', '');
                let buildName = "未知建築";
                if(Game.ObjectsById[buildId]) buildName = Game.ObjectsById[buildId].displayName;
                console.log(`🛒 [購買-建築] 建造: ${buildName}`); 
                selected.click(); 
                buyBuildingCount++; 
                nextBuyTime = Date.now() + getBuyInterval(); 
            }
        }
    }

    function getUpgradeName(element) {
        let name = "未知物品";
        try {
            const id = element.getAttribute('data-id');
            if (id && Game.UpgradesById[id]) name = `${Game.UpgradesById[id].name}`;
        } catch(e) {}
        return name;
    }

    function selectByStrategy(items, isUpgrade) {
        let itemsArray = Array.from(items).filter(item => {
            const id = item.getAttribute('data-id');
            if (isUpgrade && id === '84') return false; 
            if (!isUpgrade) {
                 const bId = item.id.replace('product', '');
                 if (Game.ObjectsById[bId] && Game.ObjectsById[bId].name === 'Wizard tower' && Game.ObjectsById[bId].amount >= MAX_WIZARD_TOWERS) return false;
            }
            return true;
        });
        if (itemsArray.length === 0) return null;
        if (buyStrategy === 'random') return itemsArray[Math.floor(Math.random() * itemsArray.length)];
        if (buyStrategy === 'cheapest') return itemsArray[0];
        return itemsArray[itemsArray.length - 1];
    }
    function startAutoBuy() {
        if (buyIntervalId) clearInterval(buyIntervalId);
        const interval = getBuyInterval();
        buyIntervalId = setInterval(autoBuy, interval);
        nextBuyTime = Date.now() + interval; autoBuy();
    }
    function stopAutoBuy() { if (buyIntervalId) clearInterval(buyIntervalId); nextBuyTime = 0; }
    function getBuyInterval() { return (buyIntervalHours * 3600 + buyIntervalMinutes * 60 + buyIntervalSeconds) * 1000; }

    // --- 股市模組 ---
    function autoStock() {
        if (!isStockEnabled || typeof Game === 'undefined') return;
        const Bank = Game.Objects['Bank'];
        if (!Bank || !Bank.minigameLoaded || !Bank.minigame) return;
        const M = Bank.minigame;

        for (let i = 0; i < M.goodsById.length; i++) {
            const good = M.goodsById[i];
            const price = M.getGoodPrice(good);
            const rv = M.getRestingVal(good.id);
            
            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(`📉 [股市] 獲利賣出 ${good.name} @ $${price.toFixed(2)} (RV: ${rv.toFixed(2)})`);
                }
            }
        }
    }

    // --- 金餅乾/糖塊/魔法模組 (v7.4.3 Logs Restored) ---
    function checkGoldenCookie() {
        if (isGoldenEnabled) {
            if (Game.canLumps() && Game.lumpCurrentType !== 3 && (Date.now() - Game.lumpT) >= Game.lumpRipeAge) Game.clickLump();
            document.querySelectorAll('#shimmers > div.shimmer').forEach(c => c.click());
        }
        if ((isSpellEnabled || isSEEnabled) && Game.Objects['Wizard tower'].minigame) {
            const M = Game.Objects['Wizard tower'].minigame;
            
            // Auto HoF
            if (isSpellEnabled && 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] 觸發連擊:命運之手'); // Restored Log
                }
            }

            // Auto SE
            if (isSEEnabled && M.magic >= M.getSpellCost(M.spells['spontaneous edifice'])) {
                if (M.magic >= M.magicM * 0.95 && Object.keys(Game.buffs).length === 0 && document.querySelectorAll('.shimmer').length === 0) {
                    console.log('🧙‍♂️ [AutoSpell] 閒置期:免費召喚了一座建築 (Spontaneous Edifice)'); // Restored Log
                    M.castSpell(M.spells['spontaneous edifice']);
                }
            }
        }
    }

    // --- 彈窗模組 (v7.4.3 Log Restored) ---
    function autoConfirmPrompt() {
        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); // Restored Log
                yesButton.click();
            }
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // 4. UI 顯示
    // ═══════════════════════════════════════════════════════════════
    function createControlPanel() {
        if (controlPanel) return;
        const panelX = GM_getValue('panelX', window.innerWidth / 2 - 200);
        const panelY = GM_getValue('panelY', 100);

        controlPanel = $(`
            <div id="cookie-control-panel" style="
                position: fixed; left: ${panelX}px; top: ${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>🍪 控制面板 v7.4.3</span>
                    <span style="font-size:12px; opacity:0.8;">Perfect Fix</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" ${isClickEnabled?'checked':''}> 👉 自動點擊</label>
                            <label><input type="checkbox" id="chk-auto-buy" ${isBuyEnabled?'checked':''}> 🛒 自動購買</label>
                            <label><input type="checkbox" id="chk-auto-golden" ${isGoldenEnabled?'checked':''}> ⭐ 金餅乾/糖塊</label>
                            <label><input type="checkbox" id="chk-auto-garden" ${isGardenEnabled?'checked':''}> 🌻 花園維護</label>
                        </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" ${isStockEnabled?'checked':''}> 股市自動交易</label>
                            <label><input type="checkbox" id="chk-se" ${isSEEnabled?'checked':''}> 🧙‍♂️ 閒置魔法: 憑空建築</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;">🌻 花園自動化 (v7.4)</div>
                        
                        <label style="display:block; margin-bottom:8px; font-weight:bold; color:#2e7d32;">
                            <input type="checkbox" id="chk-garden-overlay" ${isGardenOverlayEnabled?'checked':''}> [x] 顯示陣型輔助網格 (視覺)
                        </label>
                        <label style="display:block; margin-bottom:8px; font-weight:bold; color:#d84315;">
                            <input type="checkbox" id="chk-garden-mutation" ${isGardenMutationEnabled?'checked':''}> 🧬 啟用自動突變管理
                        </label>
                        <div style="font-size:11px; color:#666; margin-left:20px; margin-bottom:8px;">
                            (開啟後將自動鏟除 <span style="color:red">紅框(雜草/已知)</span>,並收割成熟的 <span style="color:#9c27b0">紫框(新品種)</span>)
                        </div>
                        
                        <label style="display:block; margin-bottom:8px; font-weight:bold; color:#1565c0;">
                            <input type="checkbox" id="chk-garden-smart" ${isGardenAvoidBuff?'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" ${buyStrategy==='expensive'?'selected':''}>最貴優先</option>
                            <option value="cheapest" ${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, buyIntervalMinutes, '分')}</select>
                            <select id="buy-sec">${generateOptions(0, 59, buyIntervalSeconds, '秒')}</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" ${isSpellEnabled?'checked':''}> 🧙‍♂️ 基礎魔法連擊</label>
                        <label style="display:block; font-size:13px; color:#333;"><input type="checkbox" id="chk-ui-count" ${showCountdown?'checked':''}> ⏱️ 倒數計時</label>
                        <label style="display:block; font-size:13px; color:#333;"><input type="checkbox" id="chk-ui-buff" ${showBuffMonitor?'checked':''}> 🔥 Buff 監控</label>
                        
                        <div style="margin-top:12px; color:#333;">
                            <span style="font-size:13px; font-weight:bold;">點擊速度: <span id="spd-val">${clickInterval}</span>ms</span>
                            <input type="range" id="spd-slider" min="10" max="200" value="${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, restartIntervalHours, '時')}</select>
                             <select id="rst-min">${generateOptions(0, 59, restartIntervalMinutes, '分')}</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>
        `);
        makeDraggable(controlPanel, 'panelX', 'panelY', '#panel-header');
        $('body').append(controlPanel);
        bindPanelEvents();
    }

    function createBuffDisplay() {
        if (buffDisplay) return;
        buffDisplay = $(`
            <div id="cookie-buff-monitor" style="
                position: fixed; left: ${buffX}px; top: ${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: ${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>
        `);
        makeDraggable(buffDisplay, 'buffX', 'buffY');
        $('body').append(buffDisplay);
    }
    
    function updateBuffDisplay() {
        if (!showBuffMonitor || !buffDisplay) 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)';

                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};">${buff.dname ? buff.dname : buff.name}</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);
    }

    function createCountdownDisplay() {
        if (countdownDisplay) return;
        countdownDisplay = $(`
            <div id="cookie-countdown" style="
                position: fixed; left: ${countdownX}px; top: ${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: ${showCountdown ? 'block' : 'none'};
                width: 150px; cursor: move; border: 1px solid #444;
            ">
                <div style="text-align: center; border-bottom: 1px solid #555; margin-bottom: 4px;">⏱️ 倒數計時</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">${gameVolume}</span>%</div>
                    <input type="range" id="volume-slider-mini" min="0" max="100" value="${gameVolume}" style="width:90%;">
                </div>
            </div>
        `);
        countdownDisplay.find('#volume-slider-mini').on('input', function() {
            gameVolume = parseInt($(this).val());
            $('#vol-disp').text(gameVolume);
            setGameVolume(gameVolume); GM_setValue('gameVolume', gameVolume);
        });
        makeDraggable(countdownDisplay, 'countdownX', 'countdownY');
        $('body').append(countdownDisplay);
    }
    
    function startCountdown() {
        if (countdownIntervalId) clearInterval(countdownIntervalId);
        countdownIntervalId = setInterval(() => {
            if (!showCountdown || !countdownDisplay) return;
            const now = Date.now();
            $('#txt-rst').text(formatMs(Math.max(0, nextRestartTime - now)));
            $('#txt-buy').text(isBuyEnabled ? formatMs(Math.max(0, nextBuyTime - now)) : '--:--');
        }, 1000);
    }

    function createFloatingButton() {
        if (floatingButton) return;
        floatingButton = $(`
            <div id="cookie-floating-button" style="
                position: fixed; left: ${currentX}px; top: ${currentY}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);
            ">🍪</div>
        `);
        floatingButton.click((e) => { e.stopPropagation(); toggleControlPanel(); });
        let isD = false;
        floatingButton.mousedown(() => isD = true);
        $(document).mousemove((e) => {
            if(isD) { currentX = e.clientX - 25; currentY = e.clientY - 25; floatingButton.css({left: currentX, top: currentY}); }
        }).mouseup(() => { if(isD) { isD = false; GM_setValue('buttonX', currentX); GM_setValue('buttonY', currentY); }});
        $('body').append(floatingButton);
    }
    
    function toggleControlPanel() { if (!controlPanel) createControlPanel(); controlPanel.is(':visible') ? controlPanel.fadeOut(200) : controlPanel.fadeIn(200); }
    function makeDraggable(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'))); }
        });
    }

    function bindPanelEvents() {
        $('#chk-auto-click').change(function() { isClickEnabled = this.checked; GM_setValue('isClickEnabled', isClickEnabled); isClickEnabled ? startAutoClick() : stopAutoClick(); });
        $('#chk-auto-buy').change(function() { isBuyEnabled = this.checked; GM_setValue('isBuyEnabled', isBuyEnabled); isBuyEnabled ? startAutoBuy() : stopAutoBuy(); });
        $('#chk-auto-golden').change(function() { isGoldenEnabled = this.checked; GM_setValue('isGoldenEnabled', isGoldenEnabled); });
        $('#chk-auto-garden').change(function() { isGardenEnabled = this.checked; GM_setValue('isGardenEnabled', isGardenEnabled); });
        $('#chk-stock').change(function() { isStockEnabled = this.checked; GM_setValue('isStockEnabled', isStockEnabled); });
        $('#chk-se').change(function() { isSEEnabled = this.checked; GM_setValue('isSEEnabled', isSEEnabled); });
        
        $('#chk-garden-overlay').change(function() { 
            isGardenOverlayEnabled = this.checked; GM_setValue('isGardenOverlayEnabled', isGardenOverlayEnabled); 
            if (!isGardenOverlayEnabled) $('.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');
        });
        $('#chk-garden-mutation').change(function() { isGardenMutationEnabled = this.checked; GM_setValue('isGardenMutationEnabled', isGardenMutationEnabled); });
        $('#chk-garden-smart').change(function() { isGardenAvoidBuff = this.checked; GM_setValue('isGardenAvoidBuff', isGardenAvoidBuff); });
        $('#garden-save-btn').click(saveGardenLayout);

        $('#buy-strategy').change(function() { buyStrategy = $(this).val(); GM_setValue('buyStrategy', buyStrategy); });
        $('#chk-spell').change(function() { isSpellEnabled = this.checked; GM_setValue('isSpellEnabled', isSpellEnabled); });
        $('#chk-ui-count').change(function() { showCountdown = this.checked; GM_setValue('showCountdown', showCountdown); countdownDisplay.toggle(showCountdown); });
        $('#chk-ui-buff').change(function() { showBuffMonitor = this.checked; GM_setValue('showBuffMonitor', showBuffMonitor); buffDisplay.toggle(showBuffMonitor); });
        $('#spd-slider').on('input', function() { clickInterval = parseInt($(this).val()); $('#spd-val').text(clickInterval); GM_setValue('clickInterval', clickInterval); if (isClickEnabled) startAutoClick(); });
        $('#buy-min, #buy-sec').change(function() { buyIntervalMinutes = parseInt($('#buy-min').val()); buyIntervalSeconds = parseInt($('#buy-sec').val()); GM_setValue('buyIntervalMinutes', buyIntervalMinutes); GM_setValue('buyIntervalSeconds', buyIntervalSeconds); if (isBuyEnabled) startAutoBuy(); });
        $('#rst-hr, #rst-min').change(function() { restartIntervalHours = parseInt($('#rst-hr').val()); restartIntervalMinutes = parseInt($('#rst-min').val()); GM_setValue('restartIntervalHours', restartIntervalHours); GM_setValue('restartIntervalMinutes', restartIntervalMinutes); scheduleAutoRestart(); });
        $('#btn-force-restart').click(function() { if(confirm('確定要刷新?')) performRestart(); });
    }

    function performRestart() { 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); }
    function scheduleAutoRestart() { if (restartIntervalId) clearInterval(restartIntervalId); let interval = (restartIntervalHours * 3600 + restartIntervalMinutes * 60 + restartIntervalSeconds) * 1000; if (interval < 60000) interval = 60000; nextRestartTime = Date.now() + interval; restartIntervalId = setInterval(performRestart, interval); }
    function setGameVolume(v) { try { if (Game.setVolume) Game.setVolume(v); } catch(e) {} }
    function formatMs(ms) { const s = Math.floor(ms/1000); return `${Math.floor(s/60)}:${s%60<10?'0':''}${s%60}`; }
    function 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; }
    function updateAllDisplays() { if (floatingButton) floatingButton.css('filter', isClickEnabled ? 'hue-rotate(0deg)' : 'grayscale(100%)'); }

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

})();