您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automate your garden in Cookie Clicker
// ==UserScript== // @name cookie-garden-helper // @namespace http://github.com/ // @version 0.1 // @description Automate your garden in Cookie Clicker // @author yannprada // @match https://orteil.dashnet.org/cookieclicker/ // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com // @grant none // ==/UserScript== // Ported from github without permission by ZakGhost354313 // https://github.com/yannprada/cookie-garden-helper //https://rawgit.com/yannprada/cookie-garden-helper/master/cookie-garden-helper.js { const moduleName = 'cookieGardenHelper'; const capitalize = (word) => word.charAt(0).toUpperCase() + word.slice(1); const uncapitalize = (word) => word.charAt(0).toLowerCase() + word.slice(1); const clone = (x) => JSON.parse(JSON.stringify(x)); const doc = { elId: document.getElementById.bind(document), qSel: document.querySelector.bind(document), qSelAll: document.querySelectorAll.bind(document), } class Config { static get default() { return { autoHarvest: false, autoHarvestNewSeeds: true, autoHarvestAvoidImmortals: true, autoHarvestWeeds: true, autoHarvestCleanGarden: false, autoHarvestCheckCpSMult: false, autoHarvestMiniCpSMult: { value: 1, min: 0 }, autoHarvestDying: true, autoHarvestDyingSeconds: 5, autoHarvestCheckCpSMultDying: false, autoHarvestMiniCpSMultDying: { value: 1, min: 0 }, autoPlant: false, autoPlantCheckCpSMult: false, autoPlantMaxiCpSMult: { value: 0, min: 0 }, savedPlot: [], }; } static get storageKey() { return moduleName; } static load() { let config = window.localStorage.getItem(this.storageKey); if (!config) { this.save(this.default); return this.default; } return Object.assign(this.default, JSON.parse(config)); } static save(config) { window.localStorage.setItem(this.storageKey, JSON.stringify(config)); } } class Garden { static get minigame() { return Game.Objects['Farm'].minigame; } static get isActive() { return this.minigame !== undefined; } static get CpSMult() { var res = 1 for (let key in Game.buffs) { if (typeof Game.buffs[key].multCpS != 'undefined') { res *= Game.buffs[key].multCpS; } } return res; } static get secondsBeforeNextTick() { return (this.minigame.nextStep-Date.now()) / 1000; } static get selectedSeed() { return this.minigame.seedSelected; } static set selectedSeed(seedId) { this.minigame.seedSelected = seedId; } static clonePlot() { let plot = clone(this.minigame.plot); for (let x=0; x<6; x++) { for (let y=0; y<6; y++) { let [seedId, age] = plot[x][y]; let plant = this.getPlant(seedId); if (plant != undefined && !plant.plantable) { plot[x][y] = [0, 0]; } } } return plot; } static getPlant(id) { return this.minigame.plantsById[id - 1]; } static getTile(x, y) { let tile = this.minigame.getTile(x, y); return { seedId: tile[0], age: tile[1] }; } static getPlantStage(tile) { let plant = this.getPlant(tile.seedId); if (tile.age < plant.mature) { return 'young'; } else { if ((tile.age + Math.ceil(plant.ageTick + plant.ageTickR)) < 100) { return 'mature'; } else { return 'dying'; } } } static tileIsEmpty(x, y) { return this.getTile(x, y).seedId == 0; } static plantSeed(seedId, x, y) { let plant = this.getPlant(seedId + 1); if (plant.plantable) { this.minigame.useTool(seedId, x, y); } } static forEachTile(callback) { for (let x=0; x<6; x++) { for (let y=0; y<6; y++) { if (this.minigame.isTileUnlocked(x, y)) { callback(x, y); } } } } static harvest(x, y) { this.minigame.harvest(x, y); } static fillGardenWithSelectedSeed() { if (this.selectedSeed > -1) { this.forEachTile((x, y) => { if (this.tileIsEmpty(x, y)) { this.plantSeed(this.selectedSeed, x, y); } }); } } static handleYoung(config, plant, x, y) { if (plant.weed && config.autoHarvestWeeds) { this.harvest(x, y); } let [seedId, age] = config.savedPlot[y][x]; seedId--; if (config.autoHarvestCleanGarden && ((plant.unlocked && seedId == -1) || (seedId > -1 && seedId != plant.id)) ) { this.harvest(x, y); } } static handleMature(config, plant, x, y) { if (!plant.unlocked && config.autoHarvestNewSeeds) { this.harvest(x, y); } else if (config.autoHarvestCheckCpSMult && this.CpSMult >= config.autoHarvestMiniCpSMult.value) { this.harvest(x, y); } } static handleDying(config, plant, x, y) { if (config.autoHarvestCheckCpSMultDying && this.CpSMult >= config.autoHarvestMiniCpSMultDying.value) { this.harvest(x, y); } else if (config.autoHarvestDying && this.secondsBeforeNextTick <= config.autoHarvestDyingSeconds) { this.harvest(x, y); } } static run(config) { this.forEachTile((x, y) => { if (config.autoHarvest && !this.tileIsEmpty(x, y)) { let tile = this.getTile(x, y); let plant = this.getPlant(tile.seedId); if (plant.immortal && config.autoHarvestAvoidImmortals) { // do nothing } else { let stage = this.getPlantStage(tile); switch (stage) { case 'young': this.handleYoung(config, plant, x, y); break; case 'mature': this.handleMature(config, plant, x, y); break; case 'dying': this.handleDying(config, plant, x, y); break; default: console.log(`Unexpected plant stage: ${stage}`); } } } if (config.autoPlant && (!config.autoPlantCheckCpSMult || this.CpSMult <= config.autoPlantMaxiCpSMult.value) && this.tileIsEmpty(x, y) && config.savedPlot.length > 0 ) { let [seedId, age] = config.savedPlot[y][x]; if (seedId > 0) { this.plantSeed(seedId - 1, x, y); } } }); } } class UI { static makeId(id) { return moduleName + capitalize(id); } static get css() { return ` #game.onMenu #cookieGardenHelper { display: none; } #cookieGardenHelper { background: #000 url(img/darkNoise.jpg); display: none; padding: 1em; position: inherit; } #cookieGardenHelper.visible { display: block; } #cookieGardenHelperTools:after { content: ""; display: table; clear: both; } .cookieGardenHelperPanel { float: left; width: 25%; } .cookieGardenHelperBigPanel { float: left; width: 50%; } .cookieGardenHelperSubPanel { float: left; width: 50%; } #autoHarvestPanel { color: wheat; } #autoHarvestPanel a { color: wheat; } #autoPlantPanel { color: lightgreen; } #autoPlantPanel a { color: lightgreen; } #autoHarvestPanel a:hover, #autoPlantPanel a:hover { color: white; } #cookieGardenHelperTitle { color: grey; font-size: 2em; font-style: italic; margin-bottom: 0.5em; margin-top: -0.5em; text-align: center; } #cookieGardenHelper h2 { font-size: 1.5em; line-height: 2em; } #cookieGardenHelper h3 { color: lightgrey; font-style: italic; line-height: 2em; } #cookieGardenHelper p { text-indent: 0; } #cookieGardenHelper input[type=number] { width: 3em; } #cookieGardenHelper a.toggleBtn:not(.off) .toggleBtnOff, #cookieGardenHelper a.toggleBtn.off .toggleBtnOn { display: none; } #cookieGardenHelper span.labelWithState:not(.active) .labelStateActive, #cookieGardenHelper span.labelWithState.active .labelStateNotActive { display: none; } #cookieGardenHelperTooltip { width: 300px; } #cookieGardenHelperTooltip .gardenTileRow { height: 48px; } #cookieGardenHelperTooltip .tile { border: 1px inset dimgrey; display: inline-block; height: 48px; width: 48px; } #cookieGardenHelperTooltip .gardenTileIcon { position: inherit; } #cookieGardenHelper .warning { padding: 1em; font-size: 1.5em; background-color: orange; color: white; } #cookieGardenHelper .warning .closeWarning { font-weight: bold; float: right; font-size: 2em; line-height: 0.25em; cursor: pointer; transition: 0.3s; } #cookieGardenHelper .warning .closeWarning:hover { color: black; } `; } static numberInput(name, text, title, options) { let id = this.makeId(name); return ` <input type="number" name="${name}" id="${id}" value="${options.value}" step=0.5 ${options.min !== undefined ? `min="${options.min}"` : ''} ${options.max !== undefined ? `max="${options.max}"` : ''} /> <label for="${id}" title="${title}">${text}</label>`; } static button(name, text, title, toggle, active) { if (toggle) { return `<a class="toggleBtn option ${active ? '' : 'off'}" name="${name}" id="${this.makeId(name)}" title="${title}"> ${text} <span class="toggleBtnOn">ON</span> <span class="toggleBtnOff">OFF</span> </a>`; } return `<a class="btn option" name="${name}" id="${this.makeId(name)}" title="${title}">${text}</a>`; } static toggleButton(name) { let btn = doc.qSel(`#cookieGardenHelper a.toggleBtn[name=${name}]`); btn.classList.toggle('off'); } static labelWithState(name, text, textActive, active) { return `<span name="${name}" id="${this.makeId(name)}" class="labelWithState ${active ? 'active' : ''}""> <span class="labelStateActive">${textActive}</span> <span class="labelStateNotActive">${text}</span> </span>`; } static labelToggleState(name, active) { let label = doc.qSel(`#cookieGardenHelper span.labelWithState[name=${name}]`); label.classList.toggle('active', active); } static createWarning(msg) { doc.elId('row2').insertAdjacentHTML('beforebegin', ` <div id="cookieGardenHelper"> <style>${this.css}</style> <div class="warning"> <span class="closeWarning">×</span> ${msg} </div> </div>`); doc.qSel('#cookieGardenHelper .closeWarning').onclick = (event) => { doc.elId('cookieGardenHelper').remove(); }; } static get readmeLink() { return 'https://github.com/yannprada/' + 'cookie-garden-helper/blob/master/README.md#how-it-works'; } static build(config) { doc.qSel('#row2 .productButtons').insertAdjacentHTML('beforeend', ` <div id="cookieGardenHelperProductButton" class="productButton"> Cookie Garden Helper </div>`); doc.elId('row2').insertAdjacentHTML('beforeend', ` <div id="cookieGardenHelper"> <style>${this.css}</style> <a href="${this.readmeLink}" target="new">how it works</a> <div id="cookieGardenHelperTitle" class="title">Cookie Garden Helper</div> <div id="cookieGardenHelperTools"> <div class="cookieGardenHelperBigPanel" id="autoHarvestPanel"> <h2> Auto-harvest ${this.button('autoHarvest', '', '', true, config.autoHarvest)} </h2> <div class="cookieGardenHelperSubPanel"> <h3>immortal</h3> <p> ${this.button( 'autoHarvestAvoidImmortals', 'Avoid immortals', 'Do not harvest immortal plants', true, config.autoHarvestAvoidImmortals )} </p> </div> <div class="cookieGardenHelperSubPanel"> <h3>young</h3> <p> ${this.button( 'autoHarvestWeeds', 'Remove weeds', 'Remove weeds as soon as they appear', true, config.autoHarvestWeeds )} </p> <p> ${this.button( 'autoHarvestCleanGarden', 'Clean Garden', 'Only allow saved and unlocked seeds', true, config.autoHarvestCleanGarden )} </p> </div> <div class="cookieGardenHelperSubPanel"> <h3>mature</h3> <p> ${this.button( 'autoHarvestNewSeeds', 'New seeds', 'Harvest new seeds as soon as they are mature', true, config.autoHarvestNewSeeds )} </p> <p> ${this.button( 'autoHarvestCheckCpSMult', 'Check CpS mult', 'Check the CpS multiplier before harvesting (see below)', true, config.autoHarvestCheckCpSMult )} </p> <p> ${this.numberInput( 'autoHarvestMiniCpSMult', 'Mini CpS multiplier', 'Minimum CpS multiplier for the auto-harvest to happen', config.autoHarvestMiniCpSMult )} </p> </div> <div class="cookieGardenHelperSubPanel"> <h3>dying</h3> <p> ${this.button( 'autoHarvestDying', 'Dying plants', `Harvest dying plants, ${config.autoHarvestDyingSeconds}s before ` + `the new tick occurs`, true, config.autoHarvestDying )} </p> <p> ${this.button( 'autoHarvestCheckCpSMultDying', 'Check CpS mult', 'Check the CpS multiplier before harvesting (see below)', true, config.autoHarvestCheckCpSMultDying )} </p> <p> ${this.numberInput( 'autoHarvestMiniCpSMultDying', 'Mini CpS multiplier', 'Minimum CpS multiplier for the auto-harvest to happen', config.autoHarvestMiniCpSMultDying )} </p> </div> </div> <div class="cookieGardenHelperPanel" id="autoPlantPanel"> <h2> Auto-plant ${this.button('autoPlant', '', '', true, config.autoPlant)} </h2> <p> ${this.button( 'autoPlantCheckCpSMult', 'Check CpS mult', 'Check the CpS multiplier before planting (see below)', true, config.autoPlantCheckCpSMult )} </p> <p> ${this.numberInput( 'autoPlantMaxiCpSMult', 'Maxi CpS multiplier', 'Maximum CpS multiplier for the auto-plant to happen', config.autoPlantMaxiCpSMult )} </p> <p> ${this.button('savePlot', 'Save plot', 'Save the current plot; these seeds will be replanted later')} ${this.labelWithState('plotIsSaved', 'No saved plot', 'Plot saved', Boolean(config.savedPlot.length))} </p> </div> <div class="cookieGardenHelperPanel" id="manualToolsPanel"> <h2>Manual tools</h2> <p> ${this.button('fillGardenWithSelectedSeed', 'Plant selected seed', 'Plant the selected seed on all empty tiles')} </p> </div> </div> </div>`); doc.elId('cookieGardenHelperProductButton').onclick = (event) => { doc.elId('cookieGardenHelper').classList.toggle('visible'); }; doc.qSelAll('#cookieGardenHelper input').forEach((input) => { input.onchange = (event) => { if (input.type == 'number') { let min = config[input.name].min; let max = config[input.name].max; if (min !== undefined && input.value < min) { input.value = min; } if (max !== undefined && input.value > max) { input.value = max; } Main.handleChange(input.name, input.value); } }; }); doc.qSelAll('#cookieGardenHelper a.toggleBtn').forEach((a) => { a.onclick = (event) => { Main.handleToggle(a.name); }; }); doc.qSelAll('#cookieGardenHelper a.btn').forEach((a) => { a.onclick = (event) => { Main.handleClick(a.name); }; }); doc.elId('cookieGardenHelperPlotIsSaved').onmouseout = (event) => { Main.handleMouseoutPlotIsSaved(this); } doc.elId('cookieGardenHelperPlotIsSaved').onmouseover = (event) => { Main.handleMouseoverPlotIsSaved(this); } } static getSeedIconY(seedId) { return Garden.getPlant(seedId).icon * -48; } static buildSavedPlot(savedPlot) { return `<div id="cookieGardenHelperTooltip"> ${savedPlot.map((row) => `<div class="gardenTileRow"> ${row.map((tile) => `<div class="tile"> ${(tile[0] - 1) < 0 ? '' : `<div class="gardenTileIcon" style="background-position: 0 ${this.getSeedIconY(tile[0])}px;"> </div>`} </div>`).join('')} </div>`).join('')} </div>`; } } class Main { static init() { this.timerInterval = 1000; this.config = Config.load(); UI.build(this.config); // sacrifice garden let oldConvert = Garden.minigame.convert; Garden.minigame.convert = () => { this.config.savedPlot = []; UI.labelToggleState('plotIsSaved', false); this.handleToggle('autoHarvest'); this.handleToggle('autoPlant'); this.save(); oldConvert(); } this.start(); } static start() { this.timerId = window.setInterval( () => Garden.run(this.config), this.timerInterval ); } static stop() { window.clearInterval(this.timerId); } static save() { Config.save(this.config); } static handleChange(key, value) { if (this.config[key].value !== undefined) { this.config[key].value = value; } else { this.config[key] = value; } this.save(); } static handleToggle(key) { this.config[key] = !this.config[key]; this.save(); UI.toggleButton(key); } static handleClick(key) { if (key == 'fillGardenWithSelectedSeed') { Garden.fillGardenWithSelectedSeed(); } else if (key == 'savePlot') { this.config['savedPlot'] = Garden.clonePlot(); UI.labelToggleState('plotIsSaved', true); } this.save(); } static handleMouseoutPlotIsSaved(element) { Game.tooltip.shouldHide=1; } static handleMouseoverPlotIsSaved(element) { if (this.config.savedPlot.length > 0) { let content = UI.buildSavedPlot(this.config.savedPlot); Game.tooltip.draw(element, window.escape(content)); } } } if (Garden.isActive) { Main.init(); } else { let msg = `You don't have a garden yet. This mod won't work without it!`; console.log(msg); UI.createWarning(msg); } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址