CursedSliver

Grimoire Cast Finder

Jan 17th, 2024 (edited)
976
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 30.15 KB | Source Code | 0 0
  1. var hasCCCEM = false;
  2. var hasFinder = true;
  3. var code = '';
  4. var codes = [];
  5. //first one is for global scope, second one is for sequence scope, third one is for local scope (not available to all)
  6. var limit = 9999;
  7. var pool = 1;
  8. var defaultBackfire = [0.15, 0.15, 0.15];
  9. var casts = [];
  10. var autoExecute = true;
  11. //each item represents a sequence. Goes like so: [[poolchance,defaultbackfire,[seed,cast],[seed,cast],[...]...],[...]]
  12. var preLoadedSeeds = [];
  13. var preLoadAmountPerSequence = 1;
  14. var usingPreload = false;
  15. var exceptions = null;
  16.  
  17. //for any imports to be processed
  18. //api: every item must be an array of two items. The first one contains the code. The second contains the url
  19. var instructions = [];
  20.  
  21. //Time to rip off CCCEM code
  22. function GetPromptN(input) {
  23.     if (input==0) {
  24.         Game.Prompt('<id ImportSave><noClose><h3>'+"Input code"+'</h3><div class="block">'+loc("Input or modify instructions for the Cast Finder to execute.")+'<div id="importError" class="warning" style="font-weight:bold;font-size:11px;"></div></div><div class="block"><textarea id="textareaPrompt" style="width:100%;height:256px;">'+'</textarea></div>',[['', '', 'display: none;'], [loc("Save"),';Game.ClosePrompt();code=(l(\'textareaPrompt\').value); codes = compile(code);'],loc("Cancel"),[loc("Info"),'; linking();']]);
  25.         l('textareaPrompt').focus();
  26.         l('textareaPrompt').value = code;
  27.         Game.promptOptionFocus = 0;
  28.     }
  29.     if (input==1) {
  30.         Game.Prompt('<id ImportSave><noClose><h3>'+"Input code"+'</h3><div class="block">'+loc("Modify the amount of backup seeds to preload. (whole numbers only!)")+'<div id="importError" class="warning" style="font-weight:bold;font-size:11px;"></div></div><div class="block"><textarea id="textareaPrompt" style="width:100%;height:64px;">'+'</textarea></div>',[['', '', 'display: none;'], [loc("Save"),';Game.ClosePrompt(); preLoadAmountPerSequence=parseInt(l(\'textareaPrompt\').value); updateFinder();'],loc("Cancel"),[loc("Info"),'; linking();']]);
  31.         l('textareaPrompt').focus();
  32.         l('textareaPrompt').value = preLoadAmountPerSequence;
  33.         Game.promptOptionFocus = 0;
  34.     }
  35.     if (input==2) {
  36.         Game.Prompt('<id ImportSave><noClose><h3>'+"Import preload"+'</h3><div class="block">'+loc("Import preloaded save here.")+'<div id="importError" class="warning" style="font-weight:bold;font-size:11px;"></div></div><div class="block"><textarea id="textareaPrompt" style="width:100%;height:128px;">'+'</textarea></div>',[['', '', 'display: none;'], [loc("Save"),';Game.ClosePrompt(); preLoadedSeeds=stringToArray(l(\'textareaPrompt\').value); usingPreload=true;updateFinder();'],loc("Cancel"),[loc("Info"),'; linking();']]);
  37.         l('textareaPrompt').focus();
  38.         Game.promptOptionFocus = 0;
  39.     }
  40.     if (input==3) {
  41.         let temp = arrayToString(preLoadedSeeds);
  42.         Game.Prompt('<id ExportSave><h3>'+loc("Export preload")+'</h3><div class="block">'+loc("This is your current preload code.<br>Input it with import preload to load.")+'</div><div class="block"><textarea id="textareaPrompt" style="width:100%;height:128px;" readonly>'+temp.slice(0,temp.length-1)+'</textarea></div>',[loc("All done!")])
  43.     }
  44. };
  45.  
  46. function linking(link) {
  47.     window.open('https://pastebin.com/Ej1QSF1S', '_blank');
  48. }
  49.  
  50. Game.registerMod('CastFinder', {
  51.     init:function() {
  52.         function createUpgrades() {
  53.             eval("Game.Upgrade.prototype.buy="+Game.Upgrade.prototype.buy.toString().replace('var choices=this.choicesFunction();', 'var choices=this.choicesFunction(); if (choices[0] == \"shutup\") { Game.choiceSelectorOn=-1; return 1; }'));
  54.             this.upgrades = [];
  55.             this.upgrades.push(new Game.Upgrade('Open Cast Finder', loc('Opens the Grimoire Cast Finder.<br>Will not change cast count or seed unless accessed from CCCEMUI.'),0,[20, 6]));
  56.             this.upgrades[0].pool = 'toggle'; this.upgrades[0].order = 999999; this.upgrades[0].unlocked = 1; Game.UpgradesByPool["toggle"].push(this.upgrades[0]);
  57.             this.upgrades[0].choicesFunction = function() {
  58.                 var choices = ["shutup"] //get the game to shut up about using the cohice function in unintended ways
  59.                 GetPromptN(0);
  60.                 return choices;
  61.             }
  62.             LocalizeUpgradesAndAchievs();
  63.             Game.upgradesToRebuild = 1;
  64.         }
  65.         if(Game.ready) createUpgrades()
  66.         else Game.registerHook("create", createUpgrades)
  67.     }
  68. });
  69.  
  70. //short for: Cast Finder Exceptions
  71. //actually using classes (unreal)
  72. class cfExcep {
  73.     constructor(identifier,character,values,override) {
  74.         this.id=identifier;
  75.         this.pos=character;
  76.         if (Array.isArray(values)) { this.values=values; } else { this.values=[values]; }
  77.         this.message='';
  78.         this.title='';
  79.         if (typeof override === 'function') { override(); }
  80.        
  81.         this.init();
  82.     }
  83.    
  84.     static msgs = {
  85.         'unrecognized':['Unknown entry','Unrecognized term in sequence: <b>"#1"</b>'],
  86.         'empty':['Empty entry','Sequence entries cannot empty. '],
  87.         'emptyCast':['Empty cast entry','Cast entries cannot be empty. Use an asterisk ("*") if you want to indicate any cast.'],
  88.         'find':['Invalid find depth assignment','Your input: <b>"#1"</b><br>Search depth must be a positive, whole number.'],
  89.         'pool':['Invalid pool chance assignment','Your input: <b>"#1"</b><br>Probability must be a non-negative number.'],
  90.         'modifier':['Invalid local modifier','Your modifier: <b>"#1"</b>'],
  91.         'backfireExp':['Invalid backfire expression','Your backfire expression: <b>"#1"</b>'],
  92.         'backfireExpOutOfRange1':['Backfire expression out of range','Your backfire expression: <b>"#1"</b><br>Numbers on both sides of the equal sign must be between 0 and 1. (0<=n<1)'],
  93.         'backfireExpOutOfRange2':['Backfire expression out of range','Your backfire expression: <b>"#1"</b><br>Number before the plus or minus sign must be between 0 and 1. (0<=n<1)'],
  94.         'backfireExpOutOfRange3':['Backfire expression out of range','Your backfire expression: <b>"#1"</b><br>Number before "gc" must be a non-negative, whole number.']
  95.     }
  96.    
  97.     init() {
  98.         if (cfExcep.msgs.hasOwnProperty(this.id)) {
  99.             this.message=this.fill(cfExcep.msgs[this.id][1],this.values);
  100.             this.title=cfExcep.msgs[this.id][0];
  101.             Game.Notify('Error: '+this.title,this.message,[15,5],20,0,1);
  102.         } else {
  103.             Game.Notify('Error: '+this.id,'',[15,5],20,0,1);
  104.         }
  105.     }
  106.    
  107.     fill(input, terms) {
  108.         let amount = this.count(input,'#');
  109.         for (let i = 1; i <= amount; i++) {
  110.             input=input.replace('#'+i,terms[i-1]);
  111.         }
  112.         return input;
  113.     }
  114.    
  115.     count(input, char) {
  116.         let counter = 0;
  117.         for (let i in input) {
  118.             if (input[i]==char) { counter++; }
  119.         }
  120.         return counter;
  121.     }
  122. }
  123.  
  124. //return: 1 - frenzy, 2 - lucky, 3 - cf, 4 - storm, 5 - blab, 6 - bs, 7 - storm drop, 8 - sweet, 9 - clot, 10 - ruin, 11 - cuf, 12 - ef
  125. var translator = {
  126.     'frenzy':1, 'f': 1,
  127.     'lucky':2, 'l': 2,
  128.     'clickfrenzy':3, 'cf': 3,
  129.     'bloodfrenzy':12, 'elderfrenzy':12, 'ef':12,
  130.     'cookiestorm':4, 'storm':4, 'cs': 4,
  131.     'cookiestormdrop':7, 'stormdrop':7, 'drop':7, 'sd': 7,
  132.     'buildingspecial':6, 'bs':6,
  133.     'freesugarlump':8, 'sweet!':8, 'sweet':8,
  134.     'clot':9,
  135.     'ruincookies':10, 'ruin':10,
  136.     'cursedfinger':11, 'cuf':11,
  137.     'blab': 5,
  138.     '*':0,
  139. }
  140.  
  141. var translatorReverse = Object.fromEntries(
  142.     Object.entries(translator).map(([key, value]) => [value, key])
  143. )
  144.  
  145. function generatePool() {
  146.     let thePool = [];
  147.     for (let c = 0; c < codes.length; c++) {
  148.         if (parseStatus(codes[c])) { continue; }
  149.         if (parseModifier(codes[c], 0)) { continue; }
  150.         for (let temp = 0; temp < randomFloor(pool); temp++) { thePool.push(c); }
  151.     }
  152.     return thePool;
  153. }
  154.  
  155. function chooseSequence() {
  156.     let f = choose(generatePool());
  157.     for (let c = 0; c <= f; c++) {
  158.         if (parseStatus(codes[c])) { continue; }
  159.         if (parseModifier(codes[c], 0)) { continue; }
  160.     }
  161.     console.log(codes[f]);
  162.     return codes[f];
  163. }
  164.  
  165. function interpret(minimumCastCount,f,findMult,tolog) {
  166.     if (exceptions !== null) { Game.Notify('Execution halted!','Cannot execute due the presence of compile-time errors.'); exceptions.init(); return exceptions; }
  167.     if (!Array.isArray(f)) { Game.Notify('something has gone wrong','',0); }
  168.     if (typeof findMult === 'undefined') { var findMult = 1; }
  169.     if (f.length == 0) { return 0; }
  170.     let searchHead = minimumCastCount;
  171.     let anchor = searchHead;
  172.     if (tolog) { console.log('Cast find started with depth: '+limit); }
  173.     while (searchHead < limit*findMult+minimumCastCount) {
  174.         //if (tolog) { console.log('Progress: '+(100*(searchHead/(limit*findMult+minimumCastCount))).toFixed(3)+'% ('+searchHead+')');}
  175.         //if
  176.         let found = 0;
  177.         let attempted = 0;
  178.         searchHead = anchor;
  179.         defaultBackfire[1] = defaultBackfire[0]; defaultBackfire[2] = defaultBackfire[0];
  180.         for (let c = 0; c < f.length; c++) {
  181.             //loop for attempting to find the sequence starting with finding the first cast and checking if the casts afterward satisfy the conditions
  182.             defaultBackfire[2] = defaultBackfire[1];
  183.             if (parseModifier(f[c], 1)) { continue; }
  184.             if (!found) {
  185.                 searchHead = scoutOutcomes(f[c][f[c].length - 1], searchHead+1, minimumCastCount, findMult);
  186.                 if (!searchHead) { if (!tolog) { Game.Notify('Unable to find cast! Try increasing limit.', '', 0, 0); } return false; }
  187.                 attempted = 1;
  188.                 if (!Array.isArray(f[c][0])) {
  189.                     parseModifier(['mod',f[c][0]], 2);
  190.                     if (backfireExp(1-findBackfire(searchHead), f[c][1], defaultBackfire[2])) { found = 1; anchor = searchHead; continue; }
  191.                 } else {
  192.                     if (f[c].length == 1) { found = 1; anchor = searchHead; continue; } else {
  193.                         if (backfireExp(1-findBackfire(searchHead), f[c][0], defaultBackfire[2])) { found = 1; anchor = searchHead; continue; }
  194.                     }
  195.                 }
  196.                 anchor = searchHead; found = 0; break;
  197.             } else {
  198.                 searchHead++;
  199.                 if (!outcomeEquals(findOutcome(searchHead), f[c][f[c].length-1])) { found = 0; break; }
  200.                 if (!Array.isArray(f[c][0])) {
  201.                     parseModifier(['mod',f[c][0]], 2);
  202.                     if (backfireExp(1-findBackfire(searchHead), f[c][1], defaultBackfire[2])) { continue; }
  203.                 } else {
  204.                     if (f[c].length == 1) { continue; } else {
  205.                         if (backfireExp(1-findBackfire(searchHead), f[c][0], defaultBackfire[2])) { continue; }
  206.                     }
  207.                 }
  208.                 found = 0; break;
  209.             }
  210.         }
  211.         if (found) { if (!tolog) { Game.Notify('Cast sequence found!', 'At: ' + anchor, 0, 0); } return anchor; }
  212.         if (!attempted) { Game.Notify('No casts present!', '', 0, 0); return false; }
  213.     }
  214.     return false;
  215. }
  216.  
  217. function outcomeEquals(outcome, list) {
  218.     if (!Array.isArray(list)) { list = [list]; }
  219.     if (list[0] == 0) { return true; }
  220.     if (list.includes(outcome[0])) { return true; }
  221.     if (list.includes(outcome[1])) { return true; }
  222.     return false;
  223. }
  224.  
  225. //does not parse modifiers
  226. function parseStatus(input) {
  227.     if (input[0] == 'fi') { limit = input[1]; return true; }
  228.     if (input[0] == 'ch') { pool = input[1]; return true; }
  229.     return false;
  230. }
  231.  
  232. function parseModifier(input, scope) {
  233.     //scope 2 = local
  234.     if (!Array.isArray(input)) { return false; }
  235.     if (input[0] == 'mod') { defaultBackfire[scope] = input[1]; return true; }
  236.     return false;
  237. }
  238.  
  239. function compile(input) {
  240.     exceptions = null;
  241.     let codef = [];
  242.     input = input.toString();
  243.     let loads = input;
  244.     loads = removeDuplicates(loads.match(/(import\[.*\])/));
  245.     if (typeof loads !== 'undefined') {
  246.         for (let i in loads) {
  247.             if (typeof loads[i] !== 'undefined' && loads[i] != 0) {
  248.                 loads[i] = loads[i].replace('import[').replace(']')
  249.                 LoadScript(loads[i]);
  250.             }
  251.         }
  252.     }
  253.     for (let i in instructions) {
  254.          for (let j in loads) {
  255.             if (loads[j]==instructions[i][1]) { input = input.replace('import['+instructions[i][1]+']',instructions[i][0]);break; }
  256.          }
  257.     }
  258.     codef = 0;
  259.     codef = deleteAllArr([' ', '\t', '(', ')'], input.toLowerCase());
  260.     codef = '&'+codef;
  261.     codef = treatStr(codef);
  262.     codef = codef.replaceAll('\n', ''); codef = codef.slice(1, codef.length);
  263.     codef = codef.split('&');
  264.     for (let i in codef) {
  265.         codef[i] = codef[i].split(',');
  266.     }
  267.    
  268.     //c for counter
  269.     for (let c in codef) {
  270.         //console.log('processing sequence code: '+deepCopy(codef[c]));
  271.         if (codef[c].length == 1) {
  272.             if (codef[c][0] == '') { exceptions = new cfExcep('empty',0); return exceptions; }
  273.             if (hasStatuses(codef[c][0])) { codef[c] = statuses(codef[c][0]); if (codef[c][1] instanceof cfExcep) {return exceptions; } continue; }
  274.             if (hasExpression(codef[c][0])) { codef[c].push('*'); } else {
  275.                 exceptions = new cfExcep('unrecognized',0,[codef[c][0]]); return exceptions;
  276.             }
  277.         }
  278.         if (codef[c].length > 1) {
  279.             //cc for counter in counter (for the sequence-scoped code)
  280.             for (let cc in codef[c]) {
  281.                 if (codef[c][cc] == '') { exceptions = new cfExcep('emptyCast',0); return exceptions; }
  282.                 let skipReplace = 0;
  283.                 if (typeof codef[c][cc] !== 'string') { continue; }
  284.                 let castL = []; //castL for cast local, temporary storage before pushing to cast storage
  285.                 //console.log('processing local code: '+deepCopy(codef[c][cc]));
  286.                 if (!hasModifiers(codef[c][cc])) {
  287.                     castL = codef[c][cc].split('^');
  288.                     if (castL.length > 1) {
  289.                         castL[1] = compoundEffects(castL[1]);
  290.                         if (castL[1] instanceof cfExcep) { return exceptions; }
  291.                        
  292.                         if (castL[0].includes(':')) {
  293.                             let poo = castL[0].split(':');
  294.                             if (!hasModifiers(poo[1])) { exceptions = new cfExcep('modifier',0,[poo[1]]); return exceptions; }
  295.                             castL.splice(0, 1);
  296.                             castL.splice(0, 0, poo[0]);
  297.                             castL.splice(0, 0, getDefaultBackfire(poo[1]));
  298.                         }
  299.                         let back = castL[castL.length - 2].split(';');
  300.                         //ccc for counter in counter in counter
  301.                         for (let ccc in back) {
  302.                             if (gfdSub.hasOwnProperty(back[ccc])) { back[ccc] = gfdSub[back[ccc]]; }
  303.                             let thingy = checkBackfire(back[ccc]);
  304.                             if (thingy instanceof cfExcep) { return thingy; }
  305.                         }
  306.                         castL[castL.length - 2] = back;
  307.                     } else {
  308.                         castL = [compoundEffects(codef[c][cc])];
  309.                         if (castL[0] instanceof cfExcep) { return exceptions; }
  310.                     }
  311.                 } else {
  312.                     codef[c][cc] = ['mod', getDefaultBackfire(codef[c][cc])]; skipReplace = 1;
  313.                 }
  314.                
  315.                 if (!skipReplace) { codef[c][cc] = castL; }
  316.             }
  317.         }
  318.     }
  319.     if (checkUndefined(codef)) { Game.Notify('undefined found in compiled code','Something has gone wrong and the exception system did not catch it. <b>Please contact mod developers.</b>',[7,7]); }
  320.     return codef;
  321. }
  322.  
  323. function hasExpression(input){
  324.     let k = Object.keys(translator);
  325.     for (let i in k) {
  326.         if (input.includes(k[i])) { return true; }
  327.     }
  328.     return false;
  329. }
  330.  
  331. function compoundEffects(input) {
  332.     if (typeof input !== 'string') { return false; }
  333.     if (input[0] == '*' && input !== '*') {
  334.         input = input.slice(1, input.length);
  335.         let k = removeDuplicates(Object.values(translator));
  336.         k.splice(k.indexOf(0), 1);
  337.         let sp = input.split(';');
  338.         for (let h in sp) {
  339.             if (!translator.hasOwnProperty(sp[h])) { exceptions = new cfExcep('unrecognized',0,[sp[h]]); return exceptions; }
  340.             sp[h] = translator[sp[h]];
  341.         }
  342.         for (let j in sp) {
  343.             if (k.includes(sp[j])) { k.splice(k.indexOf(sp[j]), 1); }
  344.         }
  345.         return k;
  346.     } else { let sp = input.split(';');
  347.         for (let h in sp) {
  348.             if (!translator.hasOwnProperty(sp[h])) { exceptions = new cfExcep('unrecognized',0,[sp[h]]); return exceptions; }
  349.             sp[h] = translator[sp[h]];
  350.         }
  351.         return sp;
  352.     }
  353.    
  354. }
  355.  
  356. //substitutes certain backfire notations for other
  357. var gfdSub = {
  358.     'cbg':'1=0.875','conjurebakedgoods':'1=0.875',
  359.     'fthof':'0.875=0.75','forcethehandoffate':'0.875=0.75','handoffate':'0.875=0.75',
  360.     'st':'0.75=0.625','stretchtime':'0.75=0.625',
  361.     'se':'0.625=0.5','spontaneousedifice':'0.625=0.5','edifice':'0.625=0.5',
  362.     'hc':'0.5=0.375','haggler\'scharm':'0.5=0.375','haggler\'s':'0.5=0.375','haggler':'0.5=0.375','hagglers':'0.5=0.375',
  363.     'scp':'0.375=0.25','summoncraftypixies':'0.375=0.25','craftypixies':'0.375=0.25','pixies':'0.375=0.25',
  364.     'ra':'0.25=0.125','resurrectabomination':'0.25=0.125',
  365.     'di':'0.125=0','diminishineptitude':'0.125=0','diminish':'0.125=0',
  366. }
  367.  
  368. function hasStatuses(input) {
  369.     if (Array.isArray(input)) {input = input[0]; }
  370.     if (input.includes('find:') || input.includes('p:') || hasModifiers(input)) { return true; }
  371.     return false;
  372. }
  373.  
  374. function statuses(text) {
  375.     if (typeof text !== 'string') { return 'ide'; }
  376.     //local is 0 or 1 only pls
  377.     if (text.includes('find:')) {
  378.         let temp = parseInt(text.replace('find:', ''));
  379.         if (isNaN(temp) || temp < 0) { exceptions = new cfExcep('find',0,[text.replace('find:', '')]); return exceptions; }
  380.         return ['fi', temp];
  381.     }
  382.     else if (text.includes('p:')) {
  383.         let temp = parseP(text.replace('p:', ''));
  384.         if (isNaN(temp) || temp < 0) { exceptions = new cfExcep('pool',0,[text.replace('p:', '')]); return exceptions; }
  385.         return ['ch', temp];
  386.     }
  387.     else if (hasModifiers(text)) {
  388.         return ['mod', getDefaultBackfire(text)];
  389.     }
  390.     return 'ide';
  391. }
  392.  
  393. //detects whether has only modifiers and nothing else
  394. function hasModifiers(input) {
  395.     if (Array.isArray(input)) { input = input[0]; }
  396.     if (typeof input !== 'string') { return false; }
  397.     if (input === '') { return false; }
  398.     if (input.includes('si')) { input = input.replace('si', ''); }
  399.     if (input.includes('rb')) { input = input.replace('rb', ''); }
  400.     if (input.includes('di')) { input = input.replace('di', ''); }
  401.     if (input.includes('im')) { input = input.replace('im', ''); }
  402.     if (input.includes('x')) { input = input.replace('x', ''); }
  403.     if (input != '') { return false; }
  404.     return true;
  405. }
  406.  
  407. function getDefaultBackfire(modifiers) {
  408.     if (modifiers == 'x') { return 0.15; }
  409.     var bc = 0.15;
  410.     bc *= modifiers.includes('di')?0.1:1;
  411.     bc *= modifiers.includes('im')?5:1;
  412.     bc *= (1 + (modifiers.includes('si')?0.1:0) + (modifiers.includes('rb')?0.01:0))
  413.     return bc;
  414. }
  415.  
  416. function parseP(input) {
  417.     if (input.match(/\d+%/)) { return 0.01 * parseFloat(input.replace('%', '')); }
  418.     else { return parseFloat(input); }
  419. }
  420.  
  421. function scoutOutcomes(outcomes, startPoint, offset, findMult) {
  422.     if (!Array.isArray(outcomes)) { outcomes = [outcomes]; }
  423.     if (typeof findMult === 'undefined') { var findMult = 1; }
  424.     if (outcomes == 0) { return startPoint; }
  425.     for (let i = ((typeof startPoint !== 'undefined')?startPoint:0); i < limit*findMult+offset; i++) {
  426.         let hh = findOutcome(i);
  427.         if (outcomes.includes(hh[0]) || outcomes.includes(hh[1])) { return i; }
  428.     }
  429.     return false;
  430. }
  431.  
  432. //return: 1 - frenzy, 2 - lucky, 3 - cf, 4 - storm, 5 - blab, 6 - bs, 7 - storm drop, 8 - sweet, 9 - clot, 10 - ruin, 11 - cuf, 12 - ef
  433. function findOutcome(at) {
  434.     let toReturn = [];
  435.     //success
  436.     Math.seedrandom(Game.seed + '/' + at);
  437.     Math.random(); Math.random(); Math.random();
  438.     let choices = [];
  439.     choices.push(1,2);
  440.     if (!Game.hasBuff('Dragonflight')) choices.push(3);
  441.     if (Math.random()<0.1) choices.push(4,4,5);
  442.     if (Game.BuildingsOwned>=10 && Math.random()<0.25) choices.push(6);
  443.     if (Math.random()<0.15) choices=[7];
  444.     if (Math.random()<0.0001) choices.push(8);
  445.     toReturn.push(choose(choices));
  446.        
  447.     //backfire
  448.     Math.seedrandom(Game.seed + '/' + at);
  449.     Math.random(); Math.random(); Math.random();
  450.     choices = [];
  451.     choices.push(9,10);
  452.     if (Math.random()<0.1) choices.push(11,12);
  453.     if (Math.random()<0.003) choices.push(8);
  454.     if (Math.random()<0.1) choices=[5];
  455.     toReturn.push(choose(choices));
  456.     return toReturn;
  457. }    
  458.  
  459. function findBackfire(at) {
  460.     Math.seedrandom(Game.seed + '/' + at);
  461.     return Math.random();
  462. }
  463.  
  464. function deepCopy(arr) {
  465.     if (!Array.isArray(arr)) {
  466.         return arr;
  467.     }
  468.     const copiedArray = [];
  469.     for (let i = 0; i < arr.length; i++) {
  470.     copiedArray[i] = deepCopy(arr[i]);
  471.     }
  472.     return copiedArray;
  473. }
  474.  
  475. //validates whether a backfire chance satisfies the given backfire expression(s)
  476. function backfireExp(chance, expressions, defaultBackfire) {
  477.     let exp = [];
  478.     if (Array.isArray(expressions)) { exp = expressions; } else { exp[0] = expressions; }
  479.     for (let i in exp) {
  480.         if (exp[i] == 'b' && chance <= defaultBackfire) { return true; }
  481.         if (exp[i] == 'n' && chance > defaultBackfire) { return true; }
  482.         if (exp[i] == 'bb' && chance <= Math.max(defaultBackfire,0.5)) { return true; }
  483.         if (exp[i] == 'nn' && chance > Math.max(defaultBackfire,0.5)) { return true; }
  484.         if (exp[i].includes('=')) {
  485.             //funny little hack
  486.             let ind = exp[i].indexOf('=');
  487.             if ((chance - parseP(exp[i].slice(0, ind)))*(chance - parseP(exp[i].slice(ind+1, exp[i].length))) <= 0 && Math.max(parseP(exp[i].slice(0, ind)), parseP(exp[i].slice(ind+1, exp[i].length))) != chance) {
  488.                 return true;
  489.             }
  490.         }
  491.         if (exp[i].includes('gc')) {
  492.             if (exp[i][exp[i].indexOf('gc')+2] == '+' && chance <= (parseInt(exp.slice(0, exp[i].indexOf('gc'))) * 0.15 + defaultBackfire)) { return true; }
  493.             if (exp[i][exp[i].indexOf('gc')+2] == '-' && chance > (parseInt(exp.slice(0, exp[i].indexOf('gc'))) * 0.15 + defaultBackfire)) { return true; }
  494.         } else if (exp[i].includes('+')) {
  495.             if (parseP(exp[i].slice(0, exp[i].length-1)) <= chance) { return true; }
  496.         } else if (exp[i].includes('-')) {
  497.             if (parseP(exp[i].slice(0, exp[i].length-1)) > chance) { return true; }
  498.         }
  499.     }
  500.     return false;
  501. }
  502.  
  503. function checkBackfire(input) {
  504.     if (input != 'b' && input != 'n' && input != 'bb' && input != 'nn' && !(input.includes('=')) && !(input.includes('gc')) && !(input.includes('+')) && !(input.includes('-'))) { exceptions = new cfExcep('backfireExp',0,input); return exceptions; }
  505.     if (input.includes('=')) {
  506.         let first = parseP(input.slice(0,input.indexOf('=')));
  507.         let second = parseP(input.slice(input.indexOf('=')+1,input.length));
  508.         if (isNaN(first) || isNaN(second) || !(first < 1 && first >= 0 && second < 1 && second >= 0)) {
  509.             exceptions = new cfExcep('backfireExpOutOfRange1',0,input); return exceptions;
  510.         }
  511.     }
  512.     if (input.match(/[+-]$/) !== null) {
  513.         let thet = input.slice(0,input.length-1);
  514.         let isGC = false;
  515.         if (thet.includes('gc')) { thet = parseP(thet.slice(0,thet.length-2)); isGC = true; }
  516.         else { thet = parseP(thet); }
  517.         if (isGC) {
  518.             if (isNaN(thet) || thet != Math.floor(thet) || thet < 0) {
  519.                 exceptions = new cfExcep('backfireExpOutOfRange3',0,input); return exceptions;
  520.             }
  521.         } else {
  522.             if (isNaN(thet) || !(thet < 1 && thet >= 0)) {
  523.                 exceptions = new cfExcep('backfireExpOutOfRange2',0,input); return exceptions;
  524.             }
  525.         }
  526.     }
  527.     return true;
  528. }
  529.  
  530. function removeDuplicates(input) {
  531.     let exist = [];
  532.     for (let i in input) {
  533.         if (!exist.includes(input[i])) {
  534.             exist.push(input[i]);
  535.         }
  536.     }
  537.     return exist;
  538. }
  539.  
  540. function deleteAllArr(input, text) {
  541.     for (let i in input) {
  542.         text = text.replaceAll(input[i], '');
  543.     }
  544.     return text;
  545. }
  546.  
  547. var boolConvert = {
  548.     true:'On',
  549.     false:'Off',
  550. }
  551.  
  552. function checkUndefined(input) {
  553.     if (typeof input === 'undefined') {return true;}
  554.     if (!Array.isArray(input)) {return false; }
  555.     for (let i in input) {
  556.         if (Array.isArray(input[i])) { if (checkUndefined(input[i])) { return true; } }
  557.         if (typeof input[i] === 'undefined') { return true; }
  558.     }
  559.     return false;
  560. }
  561.  
  562. function treatStr(codef) {
  563.     //brute forcing lets go
  564.     let jj = 0;
  565.     while (jj < codef.length) {
  566.         if (codef[jj]==='\n'&&codef[jj+1]!==','&&codef[jj-1]!==','&&codef[jj+1]!=='&'&&codef[jj-1]!=='&'&&codef[jj+1]!=='\n') {
  567.             if (hasExpression(codef.slice(codef.lastIndexOf('&', jj) + 1, jj))) { codef = codef.slice(0, jj) + '&' + codef.slice(jj + 1, codef.length); }
  568.             console.log('evolution: '+codef+' with '+jj);
  569.         }
  570.         jj++;
  571.     }
  572.     return codef;
  573. }
  574.  
  575. /*async function asyncInterpret(minimumCastCount) {
  576.     Game.Notify('Running code...','',0);
  577.     let result = await interpret(minimumCastCount);
  578.     return result;
  579. }*/
  580.  
  581. function preLoad() {
  582.     Game.Notify('Preloading casts...','This might take a while.',[17,19]);
  583.     Game.NotesDraw();
  584.     let thePool = [];
  585.     for (let c in codes) {
  586.         if (parseStatus(codes[c])) { continue; }
  587.         if (parseModifier(codes[c], 0)) { continue; }
  588.         thePool.push(c);
  589.     }
  590.     preLoadedSeeds = [];
  591.     let failed = 0;
  592.     for (let i in thePool) {
  593.         for (let j = 0; j < thePool[i]; j++) {
  594.             parseStatus(codes[j]);
  595.             parseModifier(codes[j],0);
  596.         }
  597.         let toPush = [pool,defaultBackfire[0]];
  598.         for (let j = 0; j < preLoadAmountPerSequence; j++) {
  599.             Game.seed=Game.makeSeed();
  600.             console.log('processing: '+arrayToString(codes[thePool[i]]));
  601.             let result = interpret(0,codes[thePool[i]],16,true);
  602.             if (result instanceof cfExcep) { return false; }
  603.             if (typeof result !== 'boolean' && result) { toPush.push([Game.seed, result]); } else { console.log(result); failed++; };
  604.         }
  605.         preLoadedSeeds.push(toPush);
  606.     }
  607.     Game.Notify('Cast preloading complete!',failed+' sequence'+((failed-1)?'':'s')+' failed.',[17,18],10000,0,1);
  608. }
  609.  
  610. function loadPreLoadedSeeds() {
  611.     if (preLoadedSeeds.length == 0) {return false;}
  612.     let pooled = [];
  613.     for (let i in preLoadedSeeds) {
  614.         if (preLoadedSeeds[i].length > 2) {
  615.             for (let temp = 0; temp < randomFloor(preLoadedSeeds[i][0]); temp++) { pooled.push(i); }
  616.         }
  617.     }
  618.     if (pooled.length == 0) {return false;}
  619.     let chosen = preLoadedSeeds[choose(pooled)];
  620.     defaultBackfire[0] = chosen[1]; chosen = choose(chosen.slice(2,chosen.length));
  621.     Game.seed=chosen[0];Game.Objects["Wizard tower"].minigame.spellsCastTotal=chosen[1];
  622. }
  623.  
  624. function arrayToString(arr) {
  625.     if (typeof arr === 'string') { return '\"'+arr+'\"'; }
  626.     if (!Array.isArray(arr)) { return arr; }
  627.     let str = '[';
  628.     for (let i in arr) {
  629.         str+=arrayToString(arr[i]);
  630.         str+=',';
  631.     }
  632.     return str.slice(0,str.length-1)+']';
  633. }
  634.  
  635. function stringToArray(str) {
  636.     eval('str='+str);
  637.     return str;
  638. }
  639.  
  640. eval('Game.Objects["Wizard tower"].minigame.draw='+Game.Objects["Wizard tower"].minigame.draw.toString().replace('Beautify(M.spellsCastTotal)','(usingPreload?"[hidden]":Beautify(M.spellsCastTotal))').replace('if (Game.drawT%5==0)','let M = Game.Objects["Wizard tower"].minigame; if (Game.drawT%5==0)'));
  641.  
  642. function CCCEMIntegratedExecute() {
  643.     Math.seedrandom(Game.seed+'+execute');
  644.     return interpret(Math.floor(Math.sqrt(Math.random())*limit),chooseSequence());
  645. }
  646.  
  647. Game.registerHook('check', function() { Game.Unlock('Open Cast Finder');});
  648.  
  649. if (typeof CCCEMUILoaded !== 'undefined') {
  650.     function updateFinder() {
  651.         castFinderButtons = [];
  652.         moreButtonsPlus[1] = [];
  653.         castFinderButtons.push('<div class="line"></div>');
  654.         castFinderButtons.push('<a class="option neatocyan" '+Game.clickStr+'="isShifting()?info(55):GetPromptN(0);RedrawCCCEM();">'+'Open Cast Finder'+'</a>');
  655.         castFinderButtons.push('<a class="option neato" '+Game.clickStr+'="isShifting()?info(56):linking();">'+'Documentation'+'</a>');
  656.         castFinderButtons.push('<a class="option neato" '+Game.clickStr+'="isShifting()?info(66):CCCEMIntegratedExecute()">'+'Execute'+'</a>');
  657.         castFinderButtons.push('<a class="option neato'+(autoExecute?'orange':'yellow')+'" '+Game.clickStr+'="isShifting()?info(57):(autoExecute=!autoExecute);updateFinder();RedrawCCCEM();">'+'Auto execute '+(boolConvert[autoExecute])+'</a><br>');
  658.         castFinderButtons.push('<a class="option neato" '+Game.clickStr+'="isShifting()?info(67):preLoad();usingPreload=true;updateFinder();RedrawCCCEM();">'+'Pre-Load</a>');
  659.         castFinderButtons.push('<a class="option neato'+(usingPreload?'orange':'yellow')+'" '+Game.clickStr+'="isShifting()?info(68):(usingPreload=!usingPreload);updateFinder();RedrawCCCEM();">'+'Use Preload '+(boolConvert[usingPreload])+'</a>');
  660.         castFinderButtons.push('<a class="option neatocyan" '+Game.clickStr+'="isShifting()?info(69):GetPromptN(1);RedrawCCCEM();">'+'Preload backups '+preLoadAmountPerSequence+'</a><br>');
  661.         castFinderButtons.push('<a class="option neatocyan" '+Game.clickStr+'="isShifting()?info(70):GetPromptN(2);RedrawCCCEM();">'+'Import preload</a>');
  662.         castFinderButtons.push('<a class="option neato" '+Game.clickStr+'="isShifting()?info(71):GetPromptN(3);RedrawCCCEM();">'+'Export current preload</a>');
  663.        
  664.         for (var i in castFinderButtons) {moreButtonsPlus[1].push(castFinderButtons[i])};
  665.         moreButtonsPlus[0] = [];
  666.         RedrawCCCEM();
  667.     }
  668.     updateFinder();
  669.     hasCCCEM = true;
  670.     code = forceFtHoF; if (forceFtHoF == "blood frenzy") { code = "b^"+code; } else {
  671.         code = "n^"+code;
  672.     }
  673.     codes = compile(code);
  674. }
Advertisement
Add Comment
Please, Sign In to add comment