├── Crustulum.js ├── Plugins ├── README.md ├── example.CrustulumPlugin.js └── perfectIdling.CrustulumPlugin.js └── README.md /Crustulum.js: -------------------------------------------------------------------------------- 1 | if (typeof Crustulum !== 'undefined') { 2 | if (Crustulum === null) { 3 | delete Crustulum; 4 | } else throw new Error('Crustulum already loaded.'); 5 | } 6 | var Crustulum = { 7 | OG: {}, // Original Game Data 8 | Game: { // Our overrides 9 | UpdateMenu: () => { 10 | Crustulum.OG.UpdateMenu(); 11 | if (Game.onMenu == 'prefs') { 12 | let fragment = document.createDocumentFragment(); 13 | fragment.appendChild(Crustulum.Menu.heading('Crustulum Toggleables')); 14 | fragment.appendChild(Crustulum.Menu.subheading('Auto Clickers')); 15 | fragment.appendChild(Crustulum.Menu.toggleButton('autoClicker','Auto Click Big Cookie','Clicks the big cookie for you.')); 16 | fragment.appendChild(Crustulum.Menu.toggleButton('autoGolden','Auto Click Golden Cookies','Clicks any golden cookies for you.')); 17 | fragment.appendChild(Crustulum.Menu.toggleButton('autoReindeer','Auto Click Reindeer','Clicks on reindeer for you')); 18 | fragment.appendChild(Crustulum.Menu.toggleButton('autoNews','Auto Click News','Clicks on the news ticker for you.')); 19 | fragment.appendChild(Crustulum.Menu.subheading('Golden Cookies')); 20 | fragment.appendChild(Crustulum.Menu.toggleButton('blockWrath','Block Wrath Cookies','Prevents wrath cookies from spawning.')); 21 | fragment.appendChild(Crustulum.Menu.subheading('Infinite Stuff')); 22 | fragment.appendChild(Crustulum.Menu.toggleButton('infiniteCookies','Infinite Cookies','Causes your cookies to constantly regenerate.')); 23 | fragment.appendChild(Crustulum.Menu.toggleButton('infiniteMagic','Infinite Magic','Causes your Grimoire magic to recharge almost instantly')); 24 | fragment.appendChild(Crustulum.Menu.toggleButton('infiniteSwaps','Infinite Swaps','Causes your Pantheon swaps to regenerate almost instantly.')); 25 | fragment.appendChild(Crustulum.Menu.subheading('Mini-game Enhancers')); 26 | fragment.appendChild(Crustulum.Menu.toggleButton('miracleSpells','Miracle Spell™','Grimoire spells will never fail.')); 27 | fragment.appendChild(Crustulum.Menu.toggleButton('immortalPlants','Make Plants Immortal','Makes it so plants never wither. Does not affect weeds or fungi.')); 28 | fragment.appendChild(Crustulum.Menu.toggleButton('neverWeeds','Never Weed™','Makes it so weeds never spawn on their own. You can still plant them and they still may spread.')); 29 | fragment.appendChild(Crustulum.Menu.toggleButton('allGodsActive','Pantheon \'R Us','All Pantheon gods except for Cyclius will be active in slot one.')); 30 | fragment.appendChild(Crustulum.Menu.toggleButton('allGodsSlotOne','Power Of The Gods','All Pantheon gods will behave as if they are in slot 1 regardless of which slot they are in.')); 31 | fragment.appendChild(Crustulum.Menu.heading('Crustulum Actions')); 32 | fragment.appendChild(Crustulum.Menu.subheading('Spawning')); 33 | fragment.appendChild(Crustulum.Menu.actionButton('spawnGolden','Spawn a Golden Cookie','Spawns a golden cookie.', Crustulum.Actions.spawnGolden)); 34 | fragment.appendChild(Crustulum.Menu.actionButton('spawnGoldenFrenzy','Spawn a Frenzy Cookie','Spawns a golden cookie that will cause a frenzy.', Crustulum.Actions.spawnGolden)); 35 | fragment.appendChild(Crustulum.Menu.actionButton('spawnGoldenDragonflight','Spawn a Dragonflight Cookie','Spawns a golden cookie that will cause a dragonflight.', Crustulum.Actions.spawnGoldenDragonflight)); 36 | fragment.appendChild(Crustulum.Menu.actionButton('giveSugarLump','Give Sugar Lump','Gives you a sugar limp.', Crustulum.Actions.giveSugarLump)); 37 | fragment.appendChild(Crustulum.Menu.actionButton('giveCookies','Give Cookies','Gives you the most cookies you can have without getting the cheated cookies achievement.', Crustulum.Actions.giveCookies)); 38 | fragment.appendChild(Crustulum.Menu.subheading('Mini-games')); 39 | fragment.appendChild(Crustulum.Menu.actionButton('refillMagic','Refill Magic','Refill all of your Grimoire\'s magic.', Crustulum.Actions.refillMagic)); 40 | fragment.appendChild(Crustulum.Menu.actionButton('refillSwaps','Refill Swaps','Refill all of your Pantheon\'s swaps', Crustulum.Actions.refillSwaps)); 41 | fragment.appendChild(Crustulum.Menu.subheading('Unlock Things')); 42 | fragment.appendChild(Crustulum.Menu.actionButton('unlockAllSeeds','Unlock Plant Seeds','Unlocks all the plant seeds for your Garden. Does not unlock weeds or fungi.', Crustulum.Actions.unlockAllSeeds)); 43 | fragment.appendChild(Crustulum.Menu.actionButton('unlockAllWeedFungusSeeds','Unlock Weed and Fungi Seeds','Unlocks all the weed and fungus seeds for the Garden.', Crustulum.Actions.unlockAllWeedFungusSeeds)); 44 | fragment.appendChild(Crustulum.Menu.actionButton('lockAllSeeds','Lock All Seeds','Locks all the seeds for the Garden except for the starting seed.', Crustulum.Actions.lockAllSeeds)); 45 | fragment.appendChild(Crustulum.Menu.subheading('Misc')); 46 | fragment.appendChild(Crustulum.Menu.actionButton('removeCheatedCookies','Remove Cheat Achievement','Remove \'Cheated cookies taste awful\' achievement', Crustulum.Actions.removeCheatedCookies)); 47 | 48 | // Unload Crustulum button. Doesn't work if you loaded other add-ons first. We check only for Cookie Monster. 49 | if (typeof CM === 'undefined' || Crustulum.cookieMonsterLoaded) fragment.appendChild(Crustulum.Menu.actionButton('unloadCrustulum','Unload Crustulum','Unloads Crustulum and disabled all of it\'s features.', Crustulum.Actions.unloadCrustulum)); 50 | 51 | Crustulum.PluginHooks.UpdateMenu(fragment); 52 | 53 | l('menu').childNodes[2].insertBefore(fragment, l('menu').childNodes[2].childNodes[l('menu').childNodes[2].childNodes.length - 1]); 54 | } 55 | }, 56 | }, 57 | Actions: { // Our action library 58 | spawnGolden: () => { 59 | Game.shimmerTypes.golden.time = Game.shimmerTypes.golden.maxTime; 60 | }, 61 | spawnGoldenFrenzy: ()=>Crustulum.Actions.spawnGoldenFixed('frenzy'), 62 | spawnGoldenDragonflight: ()=>Crustulum.Actions.spawnGoldenFixed('dragonflight'), 63 | spawnGoldenFixed: (type) => { 64 | let newShimmer = new Game.shimmer('golden',{noWrath:true}); 65 | newShimmer.dur = 10000; 66 | newShimmer.life = Math.ceil(Game.fps*newShimmer.dur); 67 | newShimmer.force = type; 68 | newShimmer.sizeMult = 2; 69 | return newShimmer; 70 | }, 71 | removeCheatedCookies: ()=>Game.RemoveAchiev('Cheated cookies taste awful'), 72 | refillMagic: ()=>{ 73 | if (Game.Objects['Wizard tower'].minigameLoaded && Game.Objects['Wizard tower'].minigame.magicM) 74 | Game.Objects['Wizard tower'].minigame.magic = Game.Objects['Wizard tower'].minigame.magicM; 75 | }, 76 | refillSwaps: ()=>{ 77 | if (Game.Objects['Temple'].minigameLoaded && Game.Objects['Temple'].minigame.gods) { 78 | Game.Objects['Temple'].minigame.swaps=3; 79 | Game.Objects['Temple'].minigame.swapT=Date.now(); 80 | Game.Objects['Temple'].minigame.lastSwapT=0; 81 | } 82 | }, 83 | giveSugarLump: ()=>{ 84 | Game.gainLumps(1); 85 | }, 86 | giveCookies: ()=>{ 87 | Game.cookies = Game.cookiesEarned; 88 | }, 89 | unlockAllSeeds: ()=>{ 90 | if(Game.Objects['Farm'].minigameLoaded && Game.Objects['Farm'].minigame.plants) { 91 | Object.keys(Game.Objects['Farm'].minigame.plants).forEach((plantName) => { 92 | let plant = Game.Objects['Farm'].minigame.plants[plantName]; 93 | if (plant.unlocked) return; 94 | if (plant.weed || plant.fungus) return; 95 | Game.Objects['Farm'].minigame.unlockSeed(plant); 96 | }); 97 | } 98 | }, 99 | unlockAllWeedFungusSeeds: ()=>{ 100 | if(Game.Objects['Farm'].minigameLoaded && Game.Objects['Farm'].minigame.plants) { 101 | Object.keys(Game.Objects['Farm'].minigame.plants).forEach((plantName) => { 102 | let plant = Game.Objects['Farm'].minigame.plants[plantName]; 103 | if (plant.unlocked) return; 104 | if (!plant.weed && !plant.fungus) return; 105 | Game.Objects['Farm'].minigame.unlockSeed(plant); 106 | }); 107 | } 108 | }, 109 | lockAllSeeds: ()=>{ 110 | if(Game.Objects['Farm'].minigameLoaded && Game.Objects['Farm'].minigame.plants) { 111 | Object.keys(Game.Objects['Farm'].minigame.plants).forEach((plantName) => { 112 | let plant = Game.Objects['Farm'].minigame.plants[plantName]; 113 | if (plant.unlocked) Game.Objects['Farm'].minigame.lockSeed(plant); 114 | }); 115 | Game.Objects['Farm'].minigame.unlockSeed(Game.Objects['Farm'].minigame.plants['bakerWheat']); 116 | } 117 | }, 118 | unloadCrustulum: ()=>{ 119 | Object.keys(Crustulum.ticks).forEach((tickThis) => { 120 | let tick = Crustulum.ticks[tickThis]; 121 | if (tick.intervalId) { 122 | clearInterval(tick.intervalId); 123 | tick.intervalId = 0; 124 | } 125 | }); 126 | Crustulum.Liberate.Game(); 127 | Crustulum.PluginHooks.UnloadPlugins(); 128 | Game.UpdateMenu(); 129 | setTimeout(() => Crustulum = null, 100); 130 | }, 131 | }, 132 | ConfigDefaults: { // The default value for the configs 133 | 'autoClicker': false, 134 | 'autoGolden': false, 135 | 'autoReindeer': false, 136 | 'autoNews': false, 137 | 'infiniteCookies': false, 138 | 'infiniteMagic': false, 139 | 'infiniteSwaps': false, 140 | 'blockWrath': false, 141 | 'immortalPlants': false, 142 | 'neverWeeds': false, 143 | 'miracleSpells': false, 144 | 'allGodsActive': false, 145 | 'allGodsSlotOne': false, 146 | }, 147 | Config: {}, // User settings 148 | Init: () => { // Initialize the add-on. 149 | if (!Game || !Game.version || !Game.updateLog) { 150 | alert('The game isn\'t loaded yet or this isn\'t the game.'); 151 | return; 152 | } 153 | Crustulum.Hijack.Game(); 154 | Crustulum.loadConfig(); 155 | Crustulum.initTicks(); 156 | Game.Win('Third-party'); 157 | if (typeof CM === 'object' && typeof Queue !== 'undefined' && typeof jscolor !== 'undefined') Crustulum.cookieMonsterLoaded = true; 158 | Crustulum.PluginHooks.Init(); 159 | }, 160 | cookieMonsterLoaded: false, 161 | Menu: { 162 | toggleButton: (configParam, text, description) => { 163 | let div = document.createElement('div'), a = document.createElement('a'), label = document.createElement('label'); 164 | if (!Crustulum.getConfig(configParam)) a.className = 'option off'; 165 | else a.className = 'option'; 166 | a.id = `crustulum-${configParam}`; 167 | a.onclick = ()=>Crustulum.toggleConfig(configParam); 168 | a.textContent = text; 169 | label.textContent = description; 170 | div.className = 'listing'; 171 | div.appendChild(a); 172 | div.appendChild(label); 173 | return div; 174 | }, 175 | actionButton: (configParam, text, description, action) => { 176 | let div = document.createElement('div'), a = document.createElement('a'), label = document.createElement('label'); 177 | a.className = 'option'; 178 | a.id = `crustulum-${configParam}`; 179 | a.onclick = action; 180 | a.textContent = text; 181 | label.textContent = description; 182 | div.className = 'listing'; 183 | div.appendChild(a); 184 | div.appendChild(label); 185 | return div; 186 | }, 187 | heading: (text) => { 188 | let heading = document.createElement('div'); 189 | heading.className = 'title'; 190 | heading.textContent = text; 191 | return heading; 192 | }, 193 | subheading: (text) => { 194 | let subheading = Crustulum.Menu.heading(text); 195 | subheading.style.fontSize = '17px'; 196 | return subheading; 197 | }, 198 | }, 199 | saveConfig: () => { 200 | localStorage.setItem('Crustulum', JSON.stringify(Crustulum.Config)); 201 | }, 202 | loadConfig: () => { 203 | let config = localStorage.getItem('Crustulum'); 204 | if (config) { 205 | config = JSON.parse(config); 206 | Object.keys(config).forEach((key) => { 207 | Crustulum.setConfig(key, config[key]); 208 | }); 209 | } 210 | }, 211 | getConfig: (configParam) => { 212 | if (typeof Crustulum.Config[configParam] === 'undefined') 213 | return Crustulum.ConfigDefaults[configParam]; 214 | else return Crustulum.Config[configParam]; 215 | }, 216 | setConfig: (configParam, configValue) => { 217 | if (configValue === Crustulum.ConfigDefaults[configParam]) 218 | delete Crustulum.Config[configParam]; 219 | else Crustulum.Config[configParam] = configValue; 220 | Crustulum.saveConfig(); 221 | return Crustulum.getConfig(configParam); 222 | }, 223 | toggleConfig: (configParam) => { 224 | let val = Crustulum.setConfig(configParam, !Crustulum.getConfig(configParam)); 225 | Crustulum.updateMenuView(configParam); 226 | return val; 227 | }, 228 | updateMenuView: (configParam) => { 229 | if (!Crustulum.getConfig(configParam)) 230 | l(`crustulum-${configParam}`).className = 'option off'; 231 | else 232 | l(`crustulum-${configParam}`).className = 'option'; 233 | }, 234 | Liberate: { 235 | Game: () => { 236 | if (Crustulum.OG.UpdateMenu) Game.UpdateMenu = Crustulum.OG.UpdateMenu; 237 | if (Crustulum.OG.shimmerPrototypeInit) Game.shimmer.prototype.init = function() { 238 | Game.shimmerTypes[this.type].initFunc(this); 239 | }; 240 | if (Game.hasGod) Crustulum.Liberate.hasGod(); 241 | Crustulum.Liberate.miniGames(); 242 | }, 243 | miniGames: () => { 244 | if(Game.Objects['Farm'].minigameLoaded && Game.Objects['Farm'].minigame.plants && Game.Objects['Farm'].minigame.soils) { 245 | if (Crustulum.OG.gardenPlantsMortality) Object.keys(Game.Objects['Farm'].minigame.plants).forEach((plantName) => { 246 | let plant = Game.Objects['Farm'].minigame.plants[plantName]; 247 | if (!plant.weed && !plant.fungus) Object.defineProperty(plant, 'immortal', {value:Crustulum.OG.gardenPlantsMortality[plantName],configurable: true}); 248 | }); 249 | 250 | if (Crustulum.OG.gardenSoilWeed) Object.keys(Game.Objects['Farm'].minigame.soils).forEach((soilName) => { 251 | let soil = Game.Objects['Farm'].minigame.soils[soilName]; 252 | Object.defineProperty(soil, 'weedMult', {value:Crustulum.OG.gardenSoilWeed[soilName],configurable: true}); 253 | }); 254 | } 255 | if(Game.Objects['Wizard tower'].minigameLoaded && Game.Objects['Wizard tower'].minigame.getFailChance) { 256 | if (Crustulum.OG.grimoireFailChance) Game.Objects['Wizard tower'].minigame.getFailChance = Crustulum.OG.grimoireFailChance; 257 | } 258 | }, 259 | hasGod: () => { 260 | if(Game.Objects['Temple'].minigameLoaded && Game.Objects['Temple'].minigame.gods && Crustulum.OG.hasGod && Game.hasGod) Game.hasGod = Crustulum.OG.hasGod; 261 | else delete Game.hasGod; 262 | }, 263 | }, 264 | Hijack: { 265 | Game: () => { 266 | if (!Crustulum.OG.UpdateMenu) { 267 | Crustulum.OG.UpdateMenu = Game.UpdateMenu; 268 | Game.UpdateMenu = Crustulum.Game.UpdateMenu; 269 | } 270 | if (!Crustulum.OG.shimmerPrototypeInit) { 271 | Crustulum.OG.shimmerPrototypeInit = true; 272 | Game.shimmer.prototype.init = function() { 273 | if (Crustulum.getConfig('blockWrath')) { 274 | this.forceObj = {'noWrath':true}; 275 | Game.shimmerTypes[this.type].initFunc(this); 276 | } else { 277 | Game.shimmerTypes[this.type].initFunc(this); 278 | } 279 | } 280 | } 281 | if (!Crustulum.OG.hasGod) Crustulum.Hijack.hasGod(); 282 | 283 | Crustulum.Hijack.miniGames(); 284 | }, 285 | miniGames: () => { 286 | if (!Crustulum) return; 287 | retry = false; 288 | 289 | if(!Game.Objects['Farm'].minigameLoaded || !Game.Objects['Farm'].minigame.plants || !Game.Objects['Farm'].minigame.soils) { 290 | retry = true; 291 | } else { 292 | if (!Crustulum.OG.gardenPlantsMortality) { 293 | Crustulum.OG.gardenPlantsMortality = {}; 294 | Object.keys(Game.Objects['Farm'].minigame.plants).forEach((plantName) => { 295 | let plant = Game.Objects['Farm'].minigame.plants[plantName]; 296 | if (!plant.weed && !plant.fungus) { 297 | Crustulum.OG.gardenPlantsMortality[plantName] = plant.immortal; 298 | Object.defineProperty(plant, 'immortal', {get:()=>{return (Crustulum.getConfig('immortalPlants')?true:Crustulum.OG.gardenPlantsMortality[plantName])},configurable: true}); 299 | } 300 | }); 301 | } 302 | 303 | if (!Crustulum.OG.gardenSoilWeed) { 304 | Crustulum.OG.gardenSoilWeed = {}; 305 | Object.keys(Game.Objects['Farm'].minigame.soils).forEach((soilName) => { 306 | let soil = Game.Objects['Farm'].minigame.soils[soilName]; 307 | Crustulum.OG.gardenSoilWeed[soilName] = soil.weedMult; 308 | Object.defineProperty(soil, 'weedMult',{get:()=>{return (Crustulum.getConfig('neverWeeds')?0:Crustulum.OG.gardenSoilWeed[soilName])},configurable: true}); 309 | }); 310 | } 311 | } 312 | 313 | if(!Game.Objects['Wizard tower'].minigameLoaded || !Game.Objects['Wizard tower'].minigame.getFailChance) { 314 | retry = true; 315 | } else { 316 | if (!Crustulum.OG.grimoireFailChance) { 317 | Crustulum.OG.grimoireFailChance = Game.Objects['Wizard tower'].minigame.getFailChance; 318 | Game.Objects['Wizard tower'].minigame.getFailChance = (spell)=>(Crustulum.getConfig('miracleSpells')?0:Crustulum.OG.grimoireFailChance(spell)); 319 | } 320 | } 321 | 322 | if (retry) setTimeout(Crustulum.Hijack.miniGames, 1000); 323 | }, 324 | hasGod: () => { 325 | if (!Crustulum) return; 326 | if(!Game.Objects['Temple'].minigameLoaded || !Game.Objects['Temple'].minigame.gods) { 327 | setTimeout(Crustulum.Hijack.hasGod, 1000); // We keep running this until we get the real Game.hasGod() 328 | } else if (!Crustulum.OG.hasGod && Game.hasGod) { 329 | Crustulum.OG.hasGod = Game.hasGod; 330 | } 331 | Game.hasGod = function(what) { 332 | if (Crustulum.getConfig('allGodsActive')) { 333 | if (['ages'].includes(what)) return false; // Add gods to this if you want to skip them 334 | return 1; 335 | } else if (Crustulum.getConfig('allGodsSlotOne')) { 336 | if(!Game.Objects['Temple'].minigameLoaded || !Game.Objects['Temple'].minigame.gods) return false; // Don't run if minigame isn't loaded (errors otherwise) 337 | let god = Game.Objects['Temple'].minigame.gods[what]; 338 | for (let i=0;i<3;i++) 339 | if (Game.Objects['Temple'].minigame.slot[i]==god.id) return 1; 340 | return false; 341 | } else { 342 | if (Crustulum.OG.hasGod) return Crustulum.OG.hasGod(what); 343 | else return false; 344 | } 345 | } 346 | }, 347 | }, 348 | initTicks: () => { 349 | Object.keys(Crustulum.ticks).forEach((tickThis) => { 350 | let tick = Crustulum.ticks[tickThis]; 351 | if (!tick.intervalId) tick.intervalId = setInterval(tick.onTick, tick.rate); 352 | }); 353 | }, 354 | ticks: { 355 | 'autoClicker': { 356 | 'intervalId': null, 357 | 'rate': 50, 358 | 'onTick': ()=>{ 359 | if (!Crustulum.getConfig('autoClicker')) return; 360 | Game.ClickCookie(); 361 | }, 362 | }, 363 | 'autoGolden': { 364 | 'intervalId': null, 365 | 'rate': 500, 366 | 'onTick': ()=>{ 367 | if (!Crustulum.getConfig('autoGolden')) return; 368 | Game.shimmers.forEach(function(shimmer) { 369 | if (shimmer.type == "golden") { shimmer.pop() } 370 | }) 371 | }, 372 | }, 373 | 'autoReindeer': { 374 | 'intervalId': null, 375 | 'rate': 500, 376 | 'onTick': ()=>{ 377 | if (!Crustulum.getConfig('autoReindeer')) return; 378 | Game.shimmers.forEach(function(shimmer) { 379 | if (shimmer.type == 'reindeer') { shimmer.pop() } 380 | }) 381 | }, 382 | }, 383 | 'autoNews': { 384 | 'intervalId': null, 385 | 'rate': 3000, 386 | 'onTick': ()=>{ 387 | if (!Crustulum.getConfig('autoNews')) return; 388 | if (Game.TickerEffect && Game.TickerEffect.type == 'fortune') Game.tickerL.click(); 389 | }, 390 | }, 391 | 'infiniteCookies': { 392 | 'intervalId': null, 393 | 'rate': 100, 394 | 'onTick': ()=>{ 395 | if (!Crustulum.getConfig('infiniteCookies')) return; 396 | Game.cookies = Game.cookiesEarned; 397 | }, 398 | }, 399 | 'infiniteMagic': { 400 | 'intervalId': null, 401 | 'rate': 1000, 402 | 'onTick': ()=>{ 403 | if (!Crustulum.getConfig('infiniteMagic')) return; 404 | if (Game.Objects['Wizard tower'].minigameLoaded && Game.Objects['Wizard tower'].minigame.magicM) 405 | Game.Objects['Wizard tower'].minigame.magic = Game.Objects['Wizard tower'].minigame.magicM; 406 | }, 407 | }, 408 | 'infiniteSwaps': { 409 | 'intervalId': null, 410 | 'rate': 1000, 411 | 'onTick': ()=>{ 412 | if (!Crustulum.getConfig('infiniteSwaps')) return; 413 | if(!Game.Objects['Temple'].minigameLoaded || !Game.Objects['Temple'].minigame.gods) return; 414 | Game.Objects['Temple'].minigame.swaps=3; 415 | Game.Objects['Temple'].minigame.swapT=Date.now(); 416 | Game.Objects['Temple'].minigame.lastSwapT=0; 417 | }, 418 | }, 419 | }, 420 | PluginHooks: { 421 | Init: () => { 422 | Object.keys(Crustulum.Plugins).forEach((key) => { 423 | let plugin = Crustulum.Plugins[key]; 424 | if (typeof plugin['Init'] === 'function') plugin['Init'](); 425 | }); 426 | }, 427 | UnloadPlugins: () => { 428 | Object.keys(Crustulum.Plugins).forEach((key) => { 429 | let plugin = Crustulum.Plugins[key]; 430 | if (typeof plugin['Unload'] === 'function') plugin['Unload'](); 431 | }); 432 | }, 433 | UpdateMenu: (fragment) => { 434 | Object.keys(Crustulum.Plugins).forEach((key) => { 435 | let plugin = Crustulum.Plugins[key]; 436 | if (typeof plugin['Game'] === 'object' && typeof plugin['Game']['UpdateMenu'] === 'function') plugin['Game']['UpdateMenu'](fragment); 437 | }); 438 | }, 439 | }, 440 | Plugins: {}, // Plugins 441 | }; 442 | 443 | // You can setup `CrustulumPlugins` (object) with your custom plugins before loading this script 444 | if (typeof CrustulumPlugins === 'object') { 445 | Object.keys(CrustulumPlugins).forEach((key) => { 446 | let plugin = CrustulumPlugins[key]; 447 | if (typeof plugin === 'object') { 448 | Crustulum.Plugins[key] = plugin; 449 | if (typeof Crustulum.Plugins[key]['Loaded'] === 'function') Crustulum.Plugins[key].Loaded(); 450 | } else if (typeof plugin === 'function') { 451 | Crustulum.Plugins[key] = plugin; 452 | Crustulum.Plugins[key](); 453 | } 454 | }); 455 | } 456 | 457 | // Alternatively, you can set CrustulumInit to false to prevent the Init and set up your plugins after loading the script, remember to call `Crustulum.Init()` afterwards. 458 | if (typeof CrustulumInit === 'undefined' || CrustulumInit) Crustulum.Init(); 459 | 460 | /* cSpell:ignore Crustulum, Toggleables, prefs, minigame, Mult, grimoire, grimoire's, grimoire\'s, Cyclius, dragonflight, Achiev, jscolor */ 461 | -------------------------------------------------------------------------------- /Plugins/README.md: -------------------------------------------------------------------------------- 1 | # Crustulum Plugins 2 | These plugins extend the features of Crustulum. I may make a feature request that I don't want in the main code as a plugin. I also may accept user submitted plugins. Most plugins must be loaded before Crustulum is loaded to work correctly. 3 | 4 | ## Available Plugins 5 | * **example** 6 | * This plugin was created as an example of how to make a plugin. It adds a button that adds 10 sugar lumps when clicked. 7 | * **perfectIdling** 8 | * Adds a button to toggle the 'Perfect idling' upgrade which makes cookies generate while the game is closed. 9 | 10 | ## How To Use 11 | To use a plugin simply run the following in the developer console (make sure to update the name): 12 | ```javascript 13 | (function () {Game.LoadMod('https://cdn.jsdelivr.net/gh/Ancyker/Crustulum/Plugins/name.CrustulumPlugin.js')}()); 14 | ``` 15 | Or you can use this bookmarklet: 16 | ```javascript 17 | javascript:(function () {Game.LoadMod('https://cdn.jsdelivr.net/gh/Ancyker/Crustulum/Plugins/name.CrustulumPlugin.js')}()); 18 | ``` 19 | -------------------------------------------------------------------------------- /Plugins/example.CrustulumPlugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample Plugin for Crustulum 3 | * 4 | * Adds a button to give you 10 sugar lumps at a time. 5 | * 6 | * Load this file and then load Crustulum 7 | */ 8 | 9 | if (typeof CrustulumPlugins !== 'object') CrustulumPlugins = {}; 10 | 11 | CrustulumPlugins['moreLumps'] = { // Functions don't need defined if they aren't used -- defined here for example only 12 | Init: () => { // Ran after Crustulum inits 13 | }, 14 | Loaded: () => { // Ran after Crustulum is loaded but before Init() is called 15 | }, 16 | Unloaded: () => { // Ran right before Crustulum unload finishes - only ran when the user clicks the unload button 17 | }, 18 | Actions: { // Only ran when we call them 19 | moreSugarLumps: ()=>{ 20 | Game.gainLumps(10); 21 | }, 22 | }, 23 | Game: { // Ran when Crustulum runs them 24 | UpdateMenu: (fragment) => { 25 | fragment.appendChild(Crustulum.Menu.subheading('Crustulum: More Lumps Add-on')); 26 | fragment.appendChild(Crustulum.Menu.actionButton('giveSugarLump','Give Sugar Lump','Gives you a sugar limp.', Crustulum.Plugins['moreLumps'].Actions.moreSugarLumps)); 27 | }, 28 | }, 29 | }; 30 | 31 | /* cSpell:ignore Crustulum */ 32 | -------------------------------------------------------------------------------- /Plugins/perfectIdling.CrustulumPlugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Perfect Idling Plugin for Crustulum 3 | * 4 | * Adds buttons to toggle the Perfect idling achievement. 5 | * 6 | * Load this file and then load Crustulum 7 | */ 8 | 9 | if (typeof CrustulumPlugins !== 'object') CrustulumPlugins = {}; 10 | 11 | CrustulumPlugins['perfectIdling'] = { 12 | Actions: { // Only ran when we call them 13 | perfectIdlingActivate: ()=>{ 14 | let upgrade = Game.Upgrades['Perfect idling']; 15 | upgrade.unlocked = 1; 16 | upgrade.bought = 1; 17 | Game.upgradesToRebuild = 1; 18 | Crustulum.Game.UpdateMenu(); 19 | }, 20 | perfectIdlingDeactivate: ()=>{ 21 | let upgrade = Game.Upgrades['Perfect idling']; 22 | upgrade.unlocked = 0; 23 | upgrade.bought = 0; 24 | Game.upgradesToRebuild = 1; 25 | Crustulum.Game.UpdateMenu(); 26 | }, 27 | }, 28 | Game: { // Ran when Crustulum runs them 29 | UpdateMenu: (fragment) => { 30 | fragment.appendChild(Crustulum.Menu.subheading('Crustulum: Perfect Idling')); 31 | if (Game.Has('Perfect idling')) fragment.appendChild(Crustulum.Menu.actionButton('perfectIdlingDeactivate','Deactivate Perfect Idling','Toggles perfect idling which makes cookies generate while the game is closed.', Crustulum.Plugins['perfectIdling'].Actions.perfectIdlingDeactivate)); 32 | else fragment.appendChild(Crustulum.Menu.actionButton('perfectIdlingActivate','Activate Perfect Idling','Toggles perfect idling which makes cookies generate while the game is closed.', Crustulum.Plugins['perfectIdling'].Actions.perfectIdlingActivate)); 33 | }, 34 | }, 35 | }; 36 | 37 | /* cSpell:ignore Crustulum, Achiev */ 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crustulum 2 | Crustulum is a *cheating* add-on for [Cookie Clicker](https://orteil.dashnet.org/cookieclicker/). It enables a variety of features to help those wishing to make aspects of the game easier. Some features provided are also done by other tools or the built in debug menus, however, this add-on simplifies some of those and does not award the "Cheated cookies taste awful" achievement. 3 | 4 | I created this add-on because it became tiresome pasting in a few snippets of code every time I reloaded the page. It's mostly for personal use but I am (obviously) sharing it anyway. No warranty of any kind is offered. I added features to this that I do not use so some things may not all be fully tested. 5 | 6 | I highly recommend not using all of the features provided as it will pretty much ruin the game if you do. You should just use it to skip parts you find tedious or improve your CpS a little bit. I personally only use the auto clicks regularly. I only use some of the actions on occasion. 7 | 8 | ## Features 9 | 10 | ### Basics 11 | * Remembers settings. 12 | * Self-serve. Nothing is forced on you. No options are enabled by default. 13 | * Compatible with [Cookie Monster](https://github.com/Aktanusa/CookieMonster), recommended to load Crustulum last. 14 | * Tested only on Chrome. 15 | 16 | ### Automation 17 | The following automation options are available. All options can be toggled on and off at will and default to being off when you first load the add-on. 18 | * **Auto Click Big Cookie** 19 | * Clicks the big cookie for you. 20 | * **Auto Click Golden Cookies** 21 | * Clicks any golden cookies for you. 22 | * **Auto Click Reindeer** 23 | * Clicks on reindeer for you 24 | * **Auto Click News** 25 | * Clicks on the news ticker for you. 26 | * **Block Wrath Cookies** 27 | * Prevents wrath cookies from spawning. 28 | * **Infinite Cookies** 29 | * Causes your cookies to constantly regenerate. 30 | * **Infinite Magic** 31 | * Causes your Grimoire magic to recharge almost instantly 32 | * **Miracle Spell™** 33 | * Grimoire spells will never fail. 34 | * **Make Plants Immortal** 35 | * Makes it so plants never wither. Does not affect weeds or fungi. 36 | * **Never Weed™** 37 | * Makes it so weeds never spawn on their own. You can still plant them and they still may spread. 38 | * **Infinite Swaps** 39 | * Causes your Pantheon swaps to regenerate almost instantly. 40 | * **Pantheon 'R Us** 41 | * All Pantheon gods except for Cyclius will be active in slot one. 42 | * **Power Of The Gods** 43 | * All Pantheon gods will behave as if they are in slot 1 regardless of which slot they are in. 44 | 45 | ### Actions 46 | A variety of actions are also available. These are once off actions and have no lasting effects. 47 | 48 | * **Spawn a Golden Cookie** 49 | * Spawns a golden cookie. 50 | * **Spawn a Frenzy Cookie** 51 | * Spawns a golden cookie that will cause a frenzy. 52 | * **Spawn a Dragonflight Cookie** 53 | * Spawns a golden cookie that will cause a dragonflight. 54 | * **Refill Magic** 55 | * Refill all of your Grimoire's magic. 56 | * **Refill Swaps** 57 | * Refill all of your Pantheon's swaps' 58 | * **Give Cookies** 59 | * Gives you the most cookies you can have without getting the cheated cookies achievement. 60 | * **Give Sugar Lump** 61 | * Gives you a sugar lump. 62 | * **Unlock Plant Seeds** 63 | * Unlocks all the plant seeds for your Garden. Does not unlock weeds or fungi. 64 | * **Unlock Weed and Fungi Seeds** 65 | * Unlocks all the weed and fungus seeds for the Garden. 66 | * **Lock All Seeds** 67 | * Locks all the seeds for the Garden except for the starting seed. 68 | * **Remove Cheat Achievement** 69 | * Remove 'Cheated cookies taste awful' achievement in case you got it before using this add-on. 70 | 71 | ## How To Use 72 | To use the add-on simply run the following in the developer console: 73 | ```javascript 74 | (function () {Game.LoadMod('https://cdn.jsdelivr.net/gh/Ancyker/Crustulum/Crustulum.js')}()); 75 | ``` 76 | Or you can use this bookmarklet: 77 | ```javascript 78 | javascript:(function () {Game.LoadMod('https://cdn.jsdelivr.net/gh/Ancyker/Crustulum/Crustulum.js')}()); 79 | ``` 80 | 81 | Note: jsDelivr is a third party service. Use at your own risk. 82 | 83 | ## Authors & Copyright Stuff 84 | I wrote all the code myself, though the original Cookie Clicker code was obviously used in some places. I also looked at Cookie Monster for reference on how to make buttons appear in the menu. 85 | --------------------------------------------------------------------------------