Guest User

[CandyBox2] Frame Advance hack v1.0

a guest
Sep 23rd, 2019
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        [CandyBox2] Frame Advance hack
  3. // @namespace   Raijinili
  4. // @include     https://candybox2.github.io/*
  5. // @include     */candybox2.github.io/*
  6. // @exclude     http://candybox2.github.io/candybox/*
  7. // @run-at      document-start
  8. // @version     1
  9. // @grant       none
  10. // @description Stops the clock and adds a way to tick.
  11. //              Call `advanceFrame()` to advance by 1 frame (10fps). (Default hotkey: apostrophe)
  12. //              Call `advanceCandies()` to advance to next 10th frame. (Default hotkey: quote mark)
  13. // ==/UserScript==
  14.  
  15.  
  16. const sourceCode = `
  17. // Frame advance hack.
  18.  
  19. //Advance 1 frame.
  20. function advanceFrame() {
  21.     curIndex++;
  22.     curIndex %= MAX_FRAME_DELAY;
  23.     if (curIndex === 0 && candyInterval) {
  24.         candyInterval();
  25.     }
  26.     callbacksTimeout[curIndex].forEach(callback => callback());
  27.     callbacksInterval.forEach(cbo => {
  28.         cbo.tick++;
  29.         if (cbo.tick >= cbo.maxTick) {
  30.             cbo.tick = 0;
  31.             cbo.call();
  32.         }
  33.     });
  34.     callbacksTimeout[curIndex] = [];
  35. }
  36.  
  37. //Advance up to 10 frames, to the next second.
  38. function advanceCandies() {
  39.     advanceFrame();
  40.     while (curIndex != 0) {
  41.         advanceFrame();
  42.     }
  43. }
  44.  
  45. //Hotkeys.
  46. //For whatever reason, this can't be in the Greasemonkey script itself.
  47. window.addEventListener('keydown', function(event) {
  48.     switch(event.key) {
  49.       case "'":
  50.         advanceFrame();
  51.         break;
  52.       case '"':
  53.         advanceCandies();
  54.         break;
  55.       default:
  56.          return;
  57.     }
  58.     event.preventDefault();
  59.     event.stopPropagation();
  60. })
  61.  
  62.  
  63. // ===================
  64.  
  65.  
  66. //Patch into setTimeout.
  67. //Note: This is assuming that nothing else in the page uses setTimeout.
  68.  
  69. var oldSetTimeout = oldSetTimeout || window.setTimeout;
  70. function newSetTimeout(callback, delay, ...args) {
  71.     if (isCandyTimeout(callback, delay)) {
  72.         /*return*/ setTimeoutFrame(callback, Math.floor(delay/100), ...args);
  73.     } else {
  74.         //probably not related to Candy Box 2.
  75.         return oldSetTimeout.call(window, callback, delay, ...args);
  76.     }
  77. }
  78.  
  79. var oldSetInterval = oldSetInterval || window.setInterval;
  80. function newSetInterval(callback, delay, ...args) {
  81.     if (isCandyInterval(callback, delay)) {
  82.         candyInterval = callback;
  83.         /*return*/ candyInterval;
  84.     } else if (isCandyTimeout(callback, delay)) {
  85.         return setIntervalFrame(callback, Math.floor(delay/100), ...args);
  86.     } else {
  87.         //probably not related to Candy Box 2.
  88.         return oldSetInterval.call(window, callback, delay, ...args);
  89.     }
  90. }
  91.  
  92.  
  93. //TODO: Be smarter about this.
  94.     //We can inspect the callback to figure out whether it's one of the three functions that Candy Box 2 uses setTimeout for.
  95.     //Candies is on interval. Quest frames is on timeout.
  96. function isCandyTimeout(callback, delay) {
  97.     return delay % 100 == 0 && delay >= 100 && delay < 1000;
  98.     //DANGER: Galaxy Wars uses non-x100 delay.
  99. }
  100.  
  101. function isCandyInterval(callback, delay) {
  102.     return delay === 1000;
  103. }
  104.  
  105. var oldClearTimeout = oldClearTimeout || window.clearTimeout;
  106. function newClearTimeout(id) {
  107.     //Check if it's one of ours.
  108.     if (isCandyTimeoutId(id)) {
  109.         //Uh what. Candy Box 2 doesn't use clearTimeout.
  110.     } else {
  111.     //Otherwise, pass it to the original clearTimeout.
  112.         return oldClearTimeout.call(window, id);
  113.     }
  114. }
  115.  
  116. function isCandyTimeoutId(id) {
  117.     return false;
  118. }
  119.  
  120. var oldClearInterval = oldClearInterval || window.clearInterval;
  121. function newClearInterval(id) {
  122.     //Check if it's one of ours.
  123.     if (typeof id === "function") {
  124.         //It's a clear function.
  125.         id();
  126.     } else {
  127.     //Otherwise, pass it to the original.
  128.         return oldClearInterval.call(window, id);
  129.     }
  130. }
  131.  
  132. var MAX_FRAME_DELAY = 10;
  133. //Array of 10 arrays of callbacks.
  134. var callbacksTimeout = Array.from({length: MAX_FRAME_DELAY}).map(()=>[]);
  135. var callbacksInterval = [];
  136. var candyInterval = null;
  137. var curIndex = 0;
  138.  
  139. function setTimeoutFrame(callback, frameDelay, ...args) {
  140.     var index = (frameDelay + curIndex) % MAX_FRAME_DELAY;
  141.     callbacksTimeout[index].push(() => callback(...args));
  142.     return callback;
  143. }
  144.  
  145. function setIntervalFrame(callback, frameDelay, ...args) {
  146.     var index = (frameDelay + curIndex) % MAX_FRAME_DELAY;
  147.     var cbObject = {
  148.         tick: 0,
  149.         maxTick: frameDelay,
  150.         call: () => callback(...args),
  151.     };
  152.     callbacksInterval.push(cbObject);
  153.     var removeCallback = () => {
  154.         callbacksInterval = callbacksInterval
  155.             .filter(obj => obj !== cbObject);
  156.     };
  157.     return removeCallback;
  158. }
  159.  
  160.  
  161.  
  162. window.setTimeout = newSetTimeout;
  163. window.setInterval = newSetInterval;
  164. window.clearTimeout = newClearTimeout;
  165. window.clearInterval = newClearInterval;
  166. window.advanceFrame = advanceFrame;
  167. window.advanceCandies = advanceCandies;
  168.  
  169. // `
  170.  
  171.  
  172. window.addEventListener('beforescriptexecute', handle);
  173. function handle(e) {
  174.     window.removeEventListener('beforescriptexecute', handle)
  175.     var script = document.createElement('script');
  176.     script.innerHTML = sourceCode + e.target.innerHTML;
  177.     document.head.appendChild(script);
  178. }
Add Comment
Please, Sign In to add comment