Automated clicker, auto-buy, auto-harvest, garden manager (Auto Mutation), stock market trader, and HUD overlay.
当前为
// ==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);
})();