Cookie Clicker Ultimate Automation

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

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴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
// @description  Automated clicker, auto-buy, auto-harvest, garden manager (Auto Mutation), stock market trader, and HUD overlay.
// @description:zh-TW 全功能自動掛機腳本:v7.4 新增花園自動突變管理 (自動鏟除雜草/收割新品種)。
// @description:zh-CN 全功能自动挂机脚本:v7.4 新增花园自动突变管理 (自动铲除杂草/收割新品种)。
// @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); // v7.4 New

    // 統計計數
    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 Loaded (Mutation Manager)');

        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. 核心功能模組 (含 v7.4 Auto Mutation)
    // ═══════════════════════════════════════════════════════════════

    // --- 花園模組 ---
    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: 異常狀態 (變異或雜草)
                    // 如果開啟了「自動突變管理」,執行 v7.4 邏輯
                    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 {
                                // 未成熟 -> 保護 (不做動作)
                                // console.log(`🛡️ [花園] 保護生長中的新品種: ${plant.name}`);
                            }
                        }
                    } else {
                        // 如果沒開突變管理,只維持基本的除草 (v7.3 舊邏輯)
                        if (plant.weed) {
                            M.harvest(x, y);
                        }
                    }
                    continue;
                }

                // 2. 自動補種 (v7.2 Smart Planting)
                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()) {
            Game.Upgrades['Elder Pledge'].buy(); nextBuyTime = Date.now() + getBuyInterval(); return;
        }
        if (isResearchEnabled) {
            const research = document.querySelectorAll('#techUpgrades .crate.upgrade.enabled');
            if (research.length > 0) { research[0].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) { 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) { selected.click(); buyBuildingCount++; nextBuyTime = Date.now() + getBuyInterval(); }
        }
    }
    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 M = Game.Objects['Bank'].minigame;
        if (!M) return;
        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 && good.stock < M.getGoodMaxStock(good) && Game.cookies > price) M.buyGood(good.id, 10000);
            if (price > rv * 1.5 && good.stock > 0) M.sellGood(good.id, 10000);
        }
    }

    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;
            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']);
            }
            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) M.castSpell(M.spells['spontaneous edifice']);
            }
        }
    }

    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))) yesButton.click();
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // 4. UI 顯示 (v7.4 Updated)
    // ═══════════════════════════════════════════════════════════════
    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</span>
                    <span style="font-size:12px; opacity:0.8;">Auto Mutation</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();
        if (Game.buffs) {
            for (let i in Game.buffs) {
                const buff = Game.buffs[i];
                const iconUrl = 'img/icons.png';
                const iconX = buff.icon[0] * 48;
                const iconY = buff.icon[1] * 48;
                buffList.append(`
                    <div style="display: flex; align-items: center; padding: 6px; background: rgba(255,255,255,0.1); border-radius: 8px;">
                        <div style="width: 48px; height: 48px; background: url(${iconUrl}) -${iconX}px -${iconY}px; margin-right: 12px; flex-shrink: 0;"></div>
                        <div>
                            <div style="font-size: 14px; font-weight: bold; color: #fff;">${buff.dname ? buff.dname : buff.name}</div>
                            <div style="font-size: 12px; color: #ccc;">剩餘: ${Math.ceil(buff.time / 30)}s</div>
                        </div>
                    </div>
                `);
            }
        }
    }

    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>
                <input type="range" id="volume-slider-mini" min="0" max="100" value="${gameVolume}" style="width:90%;">
            </div>
        `);
        countdownDisplay.find('#volume-slider-mini').on('input', function() {
            gameVolume = parseInt($(this).val()); 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);

})();