// ==UserScript== // @name Cookie Clicker Ultimate Automation // @name:zh-TW 餅乾點點樂全自動掛機輔助 (Cookie Clicker) // @name:zh-CN 饼干点点乐全自动挂机辅助 (Cookie Clicker) // @namespace http://tampermonkey.net/ // @version 8.1.0 // @description Automated clicker, auto-buy, auto-harvest, garden manager, stock market, season manager, and Santa evolver. // @description:zh-TW 全功能自動掛機腳本 v8.1.0:補回遺失的UI功能(科技開關、點擊力顯示)、優化閒置效能、強化日誌中文化。 // @author You & AI Architect // @match https://wws.justnainai.com/* // @match https://orteil.dashnet.org/cookieclicker/* // @icon https://orteil.dashnet.org/cookieclicker/img/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_openInTab // @require https://code.jquery.com/jquery-3.6.0.min.js // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // ═══════════════════════════════════════════════════════════════ // 0. 全域配置與狀態 (Configuration & State) // ═══════════════════════════════════════════════════════════════ const Config = { // 開關狀態 (預設全開) Flags: { Click: GM_getValue('isClickEnabled', true), Buy: GM_getValue('isBuyEnabled', true), Golden: GM_getValue('isGoldenEnabled', true), Spell: GM_getValue('isSpellEnabled', true), Garden: GM_getValue('isGardenEnabled', true), Research: GM_getValue('isResearchEnabled', true), // v8.1.0 Restored Stock: GM_getValue('isStockEnabled', true), SE: GM_getValue('isSEEnabled', true), Season: GM_getValue('isSeasonEnabled', true), Santa: GM_getValue('isSantaEnabled', true), GardenOverlay: GM_getValue('isGardenOverlayEnabled', true), GardenAvoidBuff: GM_getValue('isGardenAvoidBuff', true), GardenMutation: GM_getValue('isGardenMutationEnabled', false), ShowCountdown: GM_getValue('showCountdown', true), ShowBuffMonitor: GM_getValue('showBuffMonitor', true) }, // 參數 Settings: { Volume: GM_getValue('gameVolume', 50), ClickInterval: GM_getValue('clickInterval', 10), // Performance: 10ms BuyStrategy: GM_getValue('buyStrategy', 'expensive'), BuyIntervalMs: (GM_getValue('buyIntervalHours', 0) * 3600 + GM_getValue('buyIntervalMinutes', 3) * 60 + GM_getValue('buyIntervalSeconds', 0)) * 1000, RestartIntervalMs: (GM_getValue('restartIntervalHours', 1) * 3600 + GM_getValue('restartIntervalMinutes', 0) * 60 + GM_getValue('restartIntervalSeconds', 0)) * 1000, MaxWizardTowers: 800 }, // 記憶 Memory: { SavedGardenPlot: GM_getValue('savedGardenPlot', Array(6).fill().map(() => Array(6).fill(-1))), PanelX: GM_getValue('panelX', window.innerWidth / 2 - 200), PanelY: GM_getValue('panelY', 100), BuffX: GM_getValue('buffX', window.innerWidth - 340), BuffY: GM_getValue('buffY', 150), CountdownX: GM_getValue('countdownX', window.innerWidth - 170), CountdownY: GM_getValue('countdownY', 10), ButtonX: GM_getValue('buttonX', 50), ButtonY: GM_getValue('buttonY', 50) } }; // 運行時計時器與緩存 const Runtime = { Timers: { NextBuy: 0, NextRestart: 0, NextGarden: 0, NextStock: 0, NextSeasonCheck: 0 }, Stats: { ClickCount: 0, BuyUpgradeCount: 0, BuyBuildingCount: 0 }, OriginalTitle: document.title, SeasonState: { CurrentStage: 0, Roadmap: [ { name: 'Valentine', id: 'fools', target: 'BuyAllUpgrades' }, { name: 'Christmas', id: 'christmas', target: 'MaxSanta' } ] } }; // ═══════════════════════════════════════════════════════════════ // 1. UI 與 日誌模組 // ═══════════════════════════════════════════════════════════════ const UI = { Elements: { Panel: null, FloatingBtn: null, Countdown: null, BuffMonitor: null }, initStyles: function() { const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = ` .cc-overlay-missing { border: 3px dashed #2196f3 !important; box-sizing: border-box; background: rgba(33, 150, 243, 0.1); } .cc-overlay-anomaly { border: 3px solid #ff4444 !important; box-shadow: inset 0 0 15px rgba(255, 0, 0, 0.6) !important; box-sizing: border-box; z-index: 10; } .cc-overlay-new { border: 3px solid #9c27b0 !important; box-shadow: inset 0 0 15px rgba(156, 39, 176, 0.8), 0 0 10px rgba(156, 39, 176, 0.5) !important; box-sizing: border-box; z-index: 12; } .cc-overlay-correct { border: 1px solid rgba(76, 175, 80, 0.4) !important; box-sizing: border-box; } `; document.head.appendChild(style); }, formatMs: function(ms) { const s = Math.floor(ms/1000); return `${Math.floor(s/60)}:${s%60<10?'0':''}${s%60}`; }, cleanName: function(str) { if (!str) return ''; if (typeof str !== 'string') return String(str); return str.replace(/<[^>]*>/g, '').trim(); }, createFloatingButton: function() { if (this.Elements.FloatingBtn) return; this.Elements.FloatingBtn = $(` `); this.Elements.FloatingBtn.click((e) => { e.stopPropagation(); this.togglePanel(); }); let isD = false; this.Elements.FloatingBtn.mousedown(() => isD = true); $(document).mousemove((e) => { if(isD) { Config.Memory.ButtonX = e.clientX - 25; Config.Memory.ButtonY = e.clientY - 25; this.Elements.FloatingBtn.css({left: Config.Memory.ButtonX, top: Config.Memory.ButtonY}); } }).mouseup(() => { if(isD) { isD = false; GM_setValue('buttonX', Config.Memory.ButtonX); GM_setValue('buttonY', Config.Memory.ButtonY); } }); $('body').append(this.Elements.FloatingBtn); this.updateButtonState(); }, updateButtonState: function() { if (this.Elements.FloatingBtn) { this.Elements.FloatingBtn.css('filter', Config.Flags.Click ? 'hue-rotate(0deg)' : 'grayscale(100%)'); } }, createControlPanel: function() { if (this.Elements.Panel) return; const generateOptions = (min, max, sel, unit) => { let h=''; for(let i=min; i<=max; i++) h+=``; return h; }; const buyMin = Math.floor(Config.Settings.BuyIntervalMs / 60000); const buySec = (Config.Settings.BuyIntervalMs % 60000) / 1000; const rstHr = Math.floor(Config.Settings.RestartIntervalMs / 3600000); const rstMin = (Config.Settings.RestartIntervalMs % 3600000) / 60000; this.Elements.Panel = $(` `); this.makeDraggable(this.Elements.Panel, 'panelX', 'panelY', '#panel-header'); $('body').append(this.Elements.Panel); this.bindEvents(); }, togglePanel: function() { if (!this.Elements.Panel) this.createControlPanel(); this.Elements.Panel.is(':visible') ? this.Elements.Panel.fadeOut(200) : this.Elements.Panel.fadeIn(200); }, createCountdown: function() { if (this.Elements.Countdown) return; this.Elements.Countdown = $(` `); this.Elements.Countdown.find('#volume-slider-mini').on('input', function() { Config.Settings.Volume = parseInt($(this).val()); $('#vol-disp').text(Config.Settings.Volume); try { if (Game.setVolume) Game.setVolume(Config.Settings.Volume); } catch(e) {} GM_setValue('gameVolume', Config.Settings.Volume); }); this.makeDraggable(this.Elements.Countdown, 'countdownX', 'countdownY'); $('body').append(this.Elements.Countdown); }, createBuffMonitor: function() { if (this.Elements.BuffMonitor) return; this.Elements.BuffMonitor = $(` `); this.makeDraggable(this.Elements.BuffMonitor, 'buffX', 'buffY'); $('body').append(this.Elements.BuffMonitor); }, updateBuffDisplay: function() { if (!Config.Flags.ShowBuffMonitor || !this.Elements.BuffMonitor) return; const buffList = $('#buff-list-content'); buffList.empty(); let totalCpsMult = 1; let totalClickMult = 1; let hasBuff = false; if (Game.buffs) { for (let i in Game.buffs) { hasBuff = true; const buff = Game.buffs[i]; if (buff.multCpS > 0) totalCpsMult *= buff.multCpS; if (buff.multClick > 0) totalClickMult *= buff.multClick; const iconUrl = 'img/icons.png'; const iconX = buff.icon[0] * 48; const iconY = buff.icon[1] * 48; const isPowerful = buff.multCpS > 50 || buff.multClick > 10; const textColor = isPowerful ? '#ff4444' : 'white'; const bgColor = isPowerful ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.2)'; const buffName = UI.cleanName(buff.dname ? buff.dname : buff.name); let multDisplay = ''; if (buff.multCpS > 0 && buff.multCpS !== 1) multDisplay = `產量 x${Math.round(buff.multCpS*10)/10}`; if (buff.multClick > 0 && buff.multClick !== 1) { if(multDisplay) multDisplay += ', '; multDisplay += `點擊 x${Math.round(buff.multClick)}`; } buffList.append(`
${buffName}
${multDisplay}
剩餘: ${Math.ceil(buff.time / 30)}s
`); } } if (!hasBuff) buffList.append('
無活性效果
'); let summaryHtml = '
'; let effectiveClickPower = totalCpsMult * totalClickMult; if (totalCpsMult !== 1) { let val = totalCpsMult < 1 ? totalCpsMult.toFixed(2) : Math.round(totalCpsMult).toLocaleString(); summaryHtml += `
🏭 總產量: x${val}
`; } if (effectiveClickPower > 1) { let val = Math.round(effectiveClickPower).toLocaleString(); summaryHtml += `
⚡ 點擊倍率: x${val}
`; } // v8.1.0 Feature: Restore Click Power Display if (typeof Game.computedMouseCps !== 'undefined') { let clickVal = Game.computedMouseCps; let formattedClick = typeof Beautify !== 'undefined' ? Beautify(clickVal) : Math.round(clickVal).toLocaleString(); summaryHtml += `
👆 點擊力: +${formattedClick}
`; } summaryHtml += '
'; buffList.append(summaryHtml); }, makeDraggable: function(element, keyX, keyY, handleSelector = null) { let isDragging = false, startX = 0, startY = 0; const handle = handleSelector ? element.find(handleSelector) : element; handle.on('mousedown', function(e) { if ($(e.target).is('input, select, button')) return; isDragging = true; startX = e.clientX - parseInt(element.css('left')); startY = e.clientY - parseInt(element.css('top')); }); $(document).on('mousemove', function(e) { if (isDragging) element.css({left: e.clientX - startX + 'px', top: e.clientY - startY + 'px'}); }).on('mouseup', function() { if (isDragging) { isDragging = false; GM_setValue(keyX, parseInt(element.css('left'))); GM_setValue(keyY, parseInt(element.css('top'))); } }); }, bindEvents: function() { const self = this; const bindChk = (id, key) => { $('#'+id).change(function() { Config.Flags[key] = this.checked; GM_setValue('is'+key+(key.includes('Enabled')?'':'Enabled'), this.checked); if(key==='Click') self.updateButtonState(); if(key==='ShowCountdown') self.Elements.Countdown.toggle(this.checked); if(key==='ShowBuffMonitor') self.Elements.BuffMonitor.toggle(this.checked); if(key==='GardenOverlay') Logic.Garden.clearOverlay(); }); }; bindChk('chk-auto-click', 'Click'); bindChk('chk-auto-buy', 'Buy'); bindChk('chk-auto-golden', 'Golden'); bindChk('chk-auto-garden', 'Garden'); bindChk('chk-research', 'Research'); // v8.1.0 Restore bindChk('chk-stock', 'Stock'); bindChk('chk-se', 'SE'); bindChk('chk-spell', 'Spell'); bindChk('chk-ui-count', 'ShowCountdown'); bindChk('chk-ui-buff', 'ShowBuffMonitor'); bindChk('chk-garden-overlay', 'GardenOverlay'); bindChk('chk-garden-mutation', 'GardenMutation'); bindChk('chk-garden-smart', 'GardenAvoidBuff'); bindChk('chk-season', 'Season'); bindChk('chk-santa', 'Santa'); $('#garden-save-btn').click(() => Logic.Garden.saveLayout()); $('#buy-strategy').change(function() { Config.Settings.BuyStrategy = $(this).val(); GM_setValue('buyStrategy', Config.Settings.BuyStrategy); }); $('#spd-slider').on('input', function() { Config.Settings.ClickInterval = parseInt($(this).val()); $('#spd-val').text(Config.Settings.ClickInterval); GM_setValue('clickInterval', Config.Settings.ClickInterval); }); const updateBuyInt = () => { const min = parseInt($('#buy-min').val()); const sec = parseInt($('#buy-sec').val()); Config.Settings.BuyIntervalMs = (min * 60 + sec) * 1000; GM_setValue('buyIntervalMinutes', min); GM_setValue('buyIntervalSeconds', sec); }; $('#buy-min, #buy-sec').change(updateBuyInt); const updateRstInt = () => { const hr = parseInt($('#rst-hr').val()); const min = parseInt($('#rst-min').val()); Config.Settings.RestartIntervalMs = (hr * 3600 + min * 60) * 1000; Core.scheduleRestart(); GM_setValue('restartIntervalHours', hr); GM_setValue('restartIntervalMinutes', min); }; $('#rst-hr, #rst-min').change(updateRstInt); $('#btn-force-restart').click(() => { if(confirm('確定要刷新?')) Core.performRestart(); }); } }; // ═══════════════════════════════════════════════════════════════ // 2. 核心邏輯模組 (Business Logic) // ═══════════════════════════════════════════════════════════════ const Logic = { Click: { lastRun: 0, update: function(now) { // 1. 大餅乾點擊 if (Config.Flags.Click && now - this.lastRun >= Config.Settings.ClickInterval) { const bigCookie = document.querySelector('#bigCookie'); if (bigCookie) { bigCookie.click(); Runtime.Stats.ClickCount++; } this.lastRun = now; } // 2. 黃金餅乾 / 馴鹿 (高頻) if (Config.Flags.Golden) { if (Game.canLumps() && Game.lumpCurrentType !== 3 && (Date.now() - Game.lumpT) >= Game.lumpRipeAge) Game.clickLump(); document.querySelectorAll('#shimmers > div.shimmer').forEach(c => c.click()); } // 3. 魔法 this.handleSpells(); }, handleSpells: function() { if ((!Config.Flags.Spell && !Config.Flags.SE) || !Game.Objects['Wizard tower'].minigame) return; const M = Game.Objects['Wizard tower'].minigame; if (Config.Flags.Spell && M.magic >= M.getSpellCost(M.spells['hand of fate'])) { let shouldCast = false; for (let i in Game.buffs) { if (Game.buffs[i].multCpS > 7 || Game.buffs[i].multClick > 10) { shouldCast = true; break; } if (Game.buffs[i].multCpS === 7 && M.magic >= M.magicM * 0.95) { shouldCast = true; break; } } if (shouldCast) { M.castSpell(M.spells['hand of fate']); console.log('🧙‍♂️ [AutoSpell] 觸發連擊:命運之手'); } } if (Config.Flags.SE && 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)'); M.castSpell(M.spells['spontaneous edifice']); } } }, handlePrompts: function() { const yesButton = document.querySelector('#promptOption0'); if (yesButton && document.querySelector('#promptContent')) { const txt = document.querySelector('#promptContent').textContent; if (['Warning', 'One Mind', 'revoke', '警告', '不好的结果'].some(k => txt.includes(k))) { console.log('⚠️ [Safe] Auto-confirming prompt:', txt); yesButton.click(); } } } }, Buy: { update: function(now) { if (!Config.Flags.Buy || now < Runtime.Timers.NextBuy) return; if (typeof Game === 'undefined') return; // [Logic] 1. Elder Pledge (最高優先級,但須檢查冷卻) const pledge = Game.Upgrades['Elder Pledge']; if (pledge && pledge.unlocked && pledge.canBuy()) { if (typeof Game.pledgeT === 'undefined' || Game.pledgeT <= 0) { console.log('🛡️ [自動購買] 誓約過期,強制優先購買!'); pledge.buy(); Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs; return; } } // [Logic] 2. 科技研究 (Research) if (Config.Flags.Research) { const research = document.querySelectorAll('#techUpgrades .crate.upgrade.enabled'); if (research.length > 0) { const item = research[0]; let resName = "未知科技"; // v8.1.0 Improved Name Scrape: Try data-id first const dataId = item.getAttribute('data-id'); if (dataId && Game.UpgradesById[dataId]) { resName = Game.UpgradesById[dataId].dname || Game.UpgradesById[dataId].name; } else { // Fallback to regex const onMouseOver = item.getAttribute('onmouseover'); if (onMouseOver) { const match = /
(.+?)<\/div>/.exec(onMouseOver); if (match) resName = match[1]; } } console.log(`🔬 [自動購買] 研發科技:${UI.cleanName(resName)}`); item.click(); Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs; return; } } // [Logic] 3. 一般升級 (從 Data 中讀取) let affordable = Game.UpgradesInStore.filter(u => u.canBuy()); // 過濾器 affordable = affordable.filter(u => { if (u.id === 84) return false; // Covenant if (u.id === 85) return false; // Revoke Covenant if (u.id === 74) return false; // Pledge handled above // Toggle Pool Filter if (u.pool === 'toggle') { const seasonSwitchIds = [182, 183, 184, 185, 209]; if (!seasonSwitchIds.includes(u.id)) { return false; } } // Season Filter if (Config.Flags.Season) { const seasonSwitchIds = [182, 183, 184, 185, 209]; if (seasonSwitchIds.includes(u.id)) { return false; } } return true; }); if (affordable.length > 0) { if (Config.Settings.BuyStrategy === 'expensive') { affordable.sort((a, b) => b.getPrice() - a.getPrice()); } else { affordable.sort((a, b) => a.getPrice() - b.getPrice()); } const target = affordable[0]; // v8.1.0 Improved Name Scrape for Upgrades (DOM fallback) let upName = target.dname || target.name; const domUpgrade = document.querySelector(`.crate.upgrade[data-id="${target.id}"]`); if (domUpgrade) { // Attempt to extract name if dname is missing (rare but possible) } console.log(`🛒 [自動購買-升級] : ${UI.cleanName(upName)}`); target.buy(); Runtime.Stats.BuyUpgradeCount++; Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs; return; } // [Logic] 4. 建築 (從 Data 中讀取) let affordableBuildings = []; for (let i in Game.ObjectsById) { const obj = Game.ObjectsById[i]; if (obj.locked) continue; if (obj.name === 'Wizard tower' && obj.amount >= Config.Settings.MaxWizardTowers) continue; if (obj.price <= Game.cookies) { affordableBuildings.push(obj); } } if (affordableBuildings.length > 0) { if (Config.Settings.BuyStrategy === 'expensive') { affordableBuildings.sort((a, b) => b.price - a.price); } else { affordableBuildings.sort((a, b) => a.price - b.price); } const targetB = affordableBuildings[0]; let buildName = targetB.displayName || targetB.name; const domElement = document.getElementById('productName' + targetB.id); if (domElement) { buildName = domElement.innerText; } console.log(`🛒 [自動購買-建築] : ${UI.cleanName(buildName)}`); targetB.buy(1); Runtime.Stats.BuyBuildingCount++; Runtime.Timers.NextBuy = now + Config.Settings.BuyIntervalMs; } } }, Garden: { update: function(now) { if (!Config.Flags.Garden || now < Runtime.Timers.NextGarden) return; if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigameLoaded) return; const M = Game.Objects['Farm'].minigame; if (!M) return; let isCpsBuffActive = false; if (Config.Flags.GardenAvoidBuff) { for (let i in Game.buffs) { if (Game.buffs[i].multCpS > 1) { isCpsBuffActive = true; break; } } } for (let y = 0; y < 6; y++) { for (let x = 0; x < 6; x++) { if (!M.isTileUnlocked(x, y)) continue; const tile = M.plot[y][x]; const tileId = tile[0]; const tileAge = tile[1]; const savedId = Config.Memory.SavedGardenPlot[y][x]; if (tileId > 0) { const plant = M.plantsById[tileId - 1]; const isAnomaly = (savedId !== -1 && tileId !== savedId) || (savedId === -1); const plantName = UI.cleanName(plant.name); if (!isAnomaly) { if (tileAge >= 98 && tileAge >= plant.mature) M.harvest(x, y); continue; } if (Config.Flags.GardenMutation) { if (plant.unlocked) { M.harvest(x, y); console.log(`🧹 [花園] 鏟除雜物/已知變異 (紅框): ${plantName}`); } else { if (tileAge >= plant.mature) { M.harvest(x, y); console.log(`🎉 [花園] 成功收割新品種種子 (紫框): ${plantName}`); } } } else { if (plant.weed) M.harvest(x, y); } continue; } if (tileId === 0) { if (savedId !== -1 && savedId !== null) { const seed = M.plantsById[savedId - 1]; if (seed && seed.unlocked && M.canPlant(seed)) { if (Config.Flags.GardenAvoidBuff && isCpsBuffActive) continue; M.useTool(seed.id, x, y); } } } } } Runtime.Timers.NextGarden = now + 2500; }, updateOverlay: function() { if (!Config.Flags.GardenOverlay) return; if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigameLoaded) return; const M = Game.Objects['Farm'].minigame; if (!M) return; for (let y = 0; y < 6; y++) { for (let x = 0; x < 6; x++) { const tileDiv = document.getElementById(`gardenTile-${x}-${y}`); if (!tileDiv) continue; tileDiv.classList.remove('cc-overlay-missing', 'cc-overlay-anomaly', 'cc-overlay-correct', 'cc-overlay-new'); if (!M.isTileUnlocked(x, y)) continue; const savedId = Config.Memory.SavedGardenPlot[y][x]; const realId = M.plot[y][x][0]; if (realId === 0 && savedId !== -1) { tileDiv.classList.add('cc-overlay-missing'); } else if (realId !== 0) { const plant = M.plantsById[realId - 1]; const isAnomaly = (savedId !== -1 && realId !== savedId) || (savedId === -1); if (isAnomaly) { if (plant.unlocked) tileDiv.classList.add('cc-overlay-anomaly'); else tileDiv.classList.add('cc-overlay-new'); } else if (realId === savedId) { tileDiv.classList.add('cc-overlay-correct'); } } } } }, clearOverlay: function() { $('.cc-overlay-missing, .cc-overlay-anomaly, .cc-overlay-correct, .cc-overlay-new').removeClass('cc-overlay-missing cc-overlay-anomaly cc-overlay-correct cc-overlay-new'); }, saveLayout: function() { if (typeof Game === 'undefined' || !Game.Objects['Farm'].minigame) { alert('花園未就緒!'); return; } const M = Game.Objects['Farm'].minigame; let newLayout = []; for (let y = 0; y < 6; y++) { let row = []; for (let x = 0; x < 6; x++) { if (M.isTileUnlocked(x, y)) { const tile = M.plot[y][x]; row.push(tile[0] === 0 ? -1 : tile[0]); } else { row.push(-1); } } newLayout.push(row); } Config.Memory.SavedGardenPlot = newLayout; GM_setValue('savedGardenPlot', Config.Memory.SavedGardenPlot); const btn = $('#garden-save-btn'); const originalText = btn.text(); btn.text('✅ 已儲存!').css('background', '#4caf50'); setTimeout(() => btn.text(originalText).css('background', '#2196f3'), 1500); } }, Stock: { update: function(now) { if (!Config.Flags.Stock || now < Runtime.Timers.NextStock) 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); const goodName = UI.cleanName(good.name); if (price < rv * 0.5) { const maxStock = M.getGoodMaxStock(good); if (good.stock < maxStock && Game.cookies > price) { M.buyGood(good.id, 10000); } } if (price > rv * 1.5) { if (good.stock > 0) { M.sellGood(good.id, 10000); console.log(`📉 [股市] 獲利賣出 ${goodName} @ $${price.toFixed(2)} (RV: ${rv.toFixed(2)})`); } } } Runtime.Timers.NextStock = now + 3000; } }, Season: { update: function(now) { if (!Config.Flags.Season || now < Runtime.Timers.NextSeasonCheck) return; const currentStage = Runtime.SeasonState.Roadmap[Runtime.SeasonState.CurrentStage]; if (!currentStage) return; const currentSeason = Game.season; const targetSeasonId = currentStage.id; if (currentSeason !== targetSeasonId) { const switcher = Object.values(Game.Upgrades).find(u => u.toggle && u.season === targetSeasonId); if (switcher) { if (!switcher.bought && switcher.canBuy()) { console.log(`🍂 [Season] 切換季節至: ${currentStage.name}`); switcher.buy(); } } Runtime.Timers.NextSeasonCheck = now + 2000; return; } let isComplete = false; if (currentStage.target === 'BuyAllUpgrades') { const remaining = Object.values(Game.Upgrades).filter(u => u.season === targetSeasonId && !u.bought && u.unlocked); if (remaining.length === 0) isComplete = true; else { remaining.forEach(u => { if (u.canBuy()) { u.buy(); console.log(`🍂 [Season] 購買季節餅乾: ${u.name}`); } }); } } else if (currentStage.target === 'MaxSanta') { if (Game.santaLevel >= 14) { const remaining = Object.values(Game.Upgrades).filter(u => u.season === targetSeasonId && !u.bought && u.unlocked); if (remaining.length === 0) isComplete = true; } } if (isComplete) { console.log(`🍂 [Season] 階段完成: ${currentStage.name}`); Runtime.SeasonState.CurrentStage++; } Runtime.Timers.NextSeasonCheck = now + 5000; } }, Santa: { update: function(now) { if (!Config.Flags.Santa || Game.season !== 'christmas') return; if (Game.Has('A festive hat') && !Game.Has('Santa Claus')) { } if (Game.santaLevel < 14) { if (typeof Game.UpgradeSanta === 'function') { Game.UpgradeSanta(); } } } }, updateTitle: function() { if (typeof Game === 'undefined') return; let totalMult = 1; let isWorthClicking = false; if (Game.buffs) { for (let i in Game.buffs) { const buff = Game.buffs[i]; if (buff.multCpS > 0) totalMult *= buff.multCpS; if (buff.multClick > 0) totalMult *= buff.multClick; if (buff.multClick > 1 || buff.multCpS > 7) isWorthClicking = true; } } let coords = "0,0"; const bigCookie = document.querySelector('#bigCookie'); if (bigCookie) { const rect = bigCookie.getBoundingClientRect(); coords = `${Math.round(rect.left + rect.width / 2)},${Math.round(rect.top + rect.height / 2)}`; } const signal = isWorthClicking ? "⚡ATTACK" : "💤IDLE"; const displayMult = totalMult > 1000 ? (totalMult/1000).toFixed(1) + 'k' : Math.round(totalMult); document.title = `[${signal}|${displayMult}x|${coords}] ${Runtime.OriginalTitle}`; } }; // ═══════════════════════════════════════════════════════════════ // 3. 系統核心 (System Core) // ═══════════════════════════════════════════════════════════════ const Core = { init: function() { console.log('🍪 Cookie Clicker Ultimate v8.1.0 (Lost & Found Update) Loaded'); const scriptRestarted = localStorage.getItem('cookieScriptRestarted'); if (scriptRestarted) { console.log('🔄 Script restarted automatically.'); localStorage.removeItem('cookieScriptRestarted'); } UI.initStyles(); UI.createFloatingButton(); UI.createControlPanel(); UI.createCountdown(); UI.createBuffMonitor(); try { if (Game.setVolume) Game.setVolume(Config.Settings.Volume); } catch(e) {} this.scheduleRestart(); this.startHeartbeat(); setTimeout(() => { Logic.Garden.clearOverlay(); UI.updateButtonState(); }, 3000); document.addEventListener('keydown', function(e) { if (e.key === 'F8') { e.preventDefault(); Config.Flags.Click = !Config.Flags.Click; GM_setValue('isClickEnabled', Config.Flags.Click); UI.updateButtonState(); // v8.1.0 Fix: Sync Checkbox state if(UI.Elements.Panel) $('#chk-auto-click').prop('checked', Config.Flags.Click); } }); }, startHeartbeat: function() { const self = this; const fastLoop = () => { const now = Date.now(); Logic.Click.update(now); // v8.1.0 Fix: CPU Optimization // If Click is disabled, slow down the loop to 1000ms const nextDelay = Config.Flags.Click ? Math.max(10, Config.Settings.ClickInterval) : 1000; setTimeout(fastLoop, nextDelay); }; fastLoop(); setInterval(() => { const now = Date.now(); Logic.Buy.update(now); Logic.Garden.update(now); Logic.Garden.updateOverlay(); Logic.Stock.update(now); Logic.Season.update(now); Logic.Santa.update(now); Logic.updateTitle(); Logic.Click.handlePrompts(); UI.updateBuffDisplay(); if (Config.Flags.ShowCountdown) { $('#txt-rst').text(UI.formatMs(Math.max(0, Runtime.Timers.NextRestart - now))); $('#txt-buy').text(Config.Flags.Buy ? UI.formatMs(Math.max(0, Runtime.Timers.NextBuy - now)) : '--:--'); } }, 1000); }, scheduleRestart: function() { if (Runtime.Timers.RestartInterval) clearInterval(Runtime.Timers.RestartInterval); let interval = Config.Settings.RestartIntervalMs; if (interval < 60000) interval = 60000; Runtime.Timers.NextRestart = Date.now() + interval; if(this.restartTimer) clearTimeout(this.restartTimer); this.restartTimer = setTimeout(() => this.performRestart(), interval); }, performRestart: function() { if (Game.WriteSave) Game.WriteSave(); localStorage.setItem('cookieScriptRestarted', 'true'); setTimeout(() => { GM_openInTab(window.location.href, { active: true, insert: true, setParent: false }); setTimeout(() => window.close(), 1000); }, 500); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => setTimeout(() => Core.init(), 1500)); } else { setTimeout(() => Core.init(), 1500); } })();