Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name [CandyBox2] Frame Advance hack
- // @namespace Raijinili
- // @include https://candybox2.github.io/*
- // @include */candybox2.github.io/*
- // @exclude http://candybox2.github.io/candybox/*
- // @run-at document-start
- // @version 1
- // @grant none
- // @description Stops the clock and adds a way to tick.
- // Call `advanceFrame()` to advance by 1 frame (10fps). (Default hotkey: apostrophe)
- // Call `advanceCandies()` to advance to next 10th frame. (Default hotkey: quote mark)
- // ==/UserScript==
- const sourceCode = `
- // Frame advance hack.
- //Advance 1 frame.
- function advanceFrame() {
- curIndex++;
- curIndex %= MAX_FRAME_DELAY;
- if (curIndex === 0 && candyInterval) {
- candyInterval();
- }
- callbacksTimeout[curIndex].forEach(callback => callback());
- callbacksInterval.forEach(cbo => {
- cbo.tick++;
- if (cbo.tick >= cbo.maxTick) {
- cbo.tick = 0;
- cbo.call();
- }
- });
- callbacksTimeout[curIndex] = [];
- }
- //Advance up to 10 frames, to the next second.
- function advanceCandies() {
- advanceFrame();
- while (curIndex != 0) {
- advanceFrame();
- }
- }
- //Hotkeys.
- //For whatever reason, this can't be in the Greasemonkey script itself.
- window.addEventListener('keydown', function(event) {
- switch(event.key) {
- case "'":
- advanceFrame();
- break;
- case '"':
- advanceCandies();
- break;
- default:
- return;
- }
- event.preventDefault();
- event.stopPropagation();
- })
- // ===================
- //Patch into setTimeout.
- //Note: This is assuming that nothing else in the page uses setTimeout.
- var oldSetTimeout = oldSetTimeout || window.setTimeout;
- function newSetTimeout(callback, delay, ...args) {
- if (isCandyTimeout(callback, delay)) {
- /*return*/ setTimeoutFrame(callback, Math.floor(delay/100), ...args);
- } else {
- //probably not related to Candy Box 2.
- return oldSetTimeout.call(window, callback, delay, ...args);
- }
- }
- var oldSetInterval = oldSetInterval || window.setInterval;
- function newSetInterval(callback, delay, ...args) {
- if (isCandyInterval(callback, delay)) {
- candyInterval = callback;
- /*return*/ candyInterval;
- } else if (isCandyTimeout(callback, delay)) {
- return setIntervalFrame(callback, Math.floor(delay/100), ...args);
- } else {
- //probably not related to Candy Box 2.
- return oldSetInterval.call(window, callback, delay, ...args);
- }
- }
- //TODO: Be smarter about this.
- //We can inspect the callback to figure out whether it's one of the three functions that Candy Box 2 uses setTimeout for.
- //Candies is on interval. Quest frames is on timeout.
- function isCandyTimeout(callback, delay) {
- return delay % 100 == 0 && delay >= 100 && delay < 1000;
- //DANGER: Galaxy Wars uses non-x100 delay.
- }
- function isCandyInterval(callback, delay) {
- return delay === 1000;
- }
- var oldClearTimeout = oldClearTimeout || window.clearTimeout;
- function newClearTimeout(id) {
- //Check if it's one of ours.
- if (isCandyTimeoutId(id)) {
- //Uh what. Candy Box 2 doesn't use clearTimeout.
- } else {
- //Otherwise, pass it to the original clearTimeout.
- return oldClearTimeout.call(window, id);
- }
- }
- function isCandyTimeoutId(id) {
- return false;
- }
- var oldClearInterval = oldClearInterval || window.clearInterval;
- function newClearInterval(id) {
- //Check if it's one of ours.
- if (typeof id === "function") {
- //It's a clear function.
- id();
- } else {
- //Otherwise, pass it to the original.
- return oldClearInterval.call(window, id);
- }
- }
- var MAX_FRAME_DELAY = 10;
- //Array of 10 arrays of callbacks.
- var callbacksTimeout = Array.from({length: MAX_FRAME_DELAY}).map(()=>[]);
- var callbacksInterval = [];
- var candyInterval = null;
- var curIndex = 0;
- function setTimeoutFrame(callback, frameDelay, ...args) {
- var index = (frameDelay + curIndex) % MAX_FRAME_DELAY;
- callbacksTimeout[index].push(() => callback(...args));
- return callback;
- }
- function setIntervalFrame(callback, frameDelay, ...args) {
- var index = (frameDelay + curIndex) % MAX_FRAME_DELAY;
- var cbObject = {
- tick: 0,
- maxTick: frameDelay,
- call: () => callback(...args),
- };
- callbacksInterval.push(cbObject);
- var removeCallback = () => {
- callbacksInterval = callbacksInterval
- .filter(obj => obj !== cbObject);
- };
- return removeCallback;
- }
- window.setTimeout = newSetTimeout;
- window.setInterval = newSetInterval;
- window.clearTimeout = newClearTimeout;
- window.clearInterval = newClearInterval;
- window.advanceFrame = advanceFrame;
- window.advanceCandies = advanceCandies;
- // `
- window.addEventListener('beforescriptexecute', handle);
- function handle(e) {
- window.removeEventListener('beforescriptexecute', handle)
- var script = document.createElement('script');
- script.innerHTML = sourceCode + e.target.innerHTML;
- document.head.appendChild(script);
- }
Add Comment
Please, Sign In to add comment