Degritone

Dollars BBS idle game

Feb 25th, 2022 (edited)
636
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name             BBSIdle
  3. // @namespace        dollars-bbs.org
  4. // @author           Degritone
  5. // @description      Adds BBSIdle to the BBS
  6. // @match            *://dollars-bbs.org/*
  7. // @grant            GM.setValue
  8. // @grant            GM.getValue
  9. // ==/UserScript==
  10.  
  11. let validBoards = /\/(main|intro|countries|missions|suggestions|news|animation|art|comics|films|food|games|vn|literature|music|personal|sports|tech|random|test)(\/index.html)?/;
  12. let boardsArray = ["main","intro","countries","missions","suggestions","news","animation","art","comics","films","food","games","vn","literature","music","personal","sports","tech","random","test"];
  13. let dayInterval = 1000*60*60*23;
  14.  
  15. let checkVisible = function(elm){
  16.   let rect = elm.getBoundingClientRect();
  17.   let viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
  18.   let visPercent = 0;
  19.   if(rect.top < viewHeight && rect.bottom > 0){
  20.     visPercent = (rect.height-(rect.top<0?-rect.top:0)-(rect.bottom>viewHeight?rect.bottom-viewHeight:0))/rect.height;
  21.   }
  22.   return visPercent;
  23. }
  24.  
  25. let viewCircle = function(thread,board,number){
  26.   this.board = board;
  27.   this.number = number;
  28.   this.parent = thread;
  29.   this.parent.children[1].style.position = "relative";
  30.   this.size = 25;
  31.   this.element = document.createElement("canvas");
  32.   this.parent.children[1].appendChild(this.element);
  33.   this.element.width = this.size;
  34.   this.element.height = this.size;
  35.   this.element.style.cssText = "width:25px;height:25px;position:absolute;right:7px;top:4px;";
  36.   this.context = this.element.getContext("2d");
  37.   this.viewed = 0;
  38.   this.full = false;
  39.   let today = new Date()*1;
  40.   this.reset = async()=>{
  41.     this.viewed = parseInt(await GM.getValue("bbsidle."+board+"."+number,0));
  42.     if(today-this.viewed>dayInterval){
  43.       this.viewed = today;
  44.     }
  45.     this.visible = this.viewed==today?0:(dayInterval-(today-this.viewed))/dayInterval*20000;
  46.   }
  47.   this.reset();
  48.   this.visible = false;
  49.   this.lastTime = false;
  50.   this.draw = async(obj)=>{
  51.     if(!this.visible);
  52.     if(obj.number==0)
  53.       getActiveCircle();
  54.     if(activeCircle == obj){
  55.       let size = obj.size;
  56.       let now = new Date()*1;
  57.       if(!obj.lastTime){
  58.         obj.lastTime = now;
  59.         obj.context.beginPath();
  60.         obj.context.arc(size/2,size/2,size/2-2,0,2*Math.PI);
  61.         obj.context.lineWidth = 3;
  62.         obj.context.strokeStyle = "#BBBBBB";
  63.         obj.context.stroke();
  64.       }
  65.       obj.visible += now-obj.lastTime*1;
  66.       obj.lastTime = now;
  67.       if(obj.visible>=20000 && !obj.full){
  68.         obj.full = true;
  69.         await GM.setValue("bbsidle."+obj.board+"."+obj.number,obj.lastTime*1);
  70.         if(multSet){
  71.           multSet = false;
  72.           calculateMultiplier();
  73.         }
  74.       }
  75.       obj.context.beginPath();
  76.       obj.context.moveTo(size/2,size/2);
  77.       obj.context.lineTo(size/2,3);
  78.       obj.context.arc(size/2,size/2,size/2-3,1.5*Math.PI,1.5*Math.PI+(obj.full?20000:obj.visible)*2*Math.PI/20000);
  79.       obj.context.fillStyle = "rgb("+(obj.full?0:Math.log(20000-obj.visible+0.01)/Math.log(20000)*255)+","+(obj.full?255:obj.visible/20000*305)+",75)";
  80.       obj.context.fill();
  81.     }else if(obj.lastTime){
  82.       obj.lastTime = new Date()*1+100;
  83.     }
  84.   }
  85.   setInterval(this.draw,100,this);
  86. }
  87.  
  88. let threads = [];
  89. let circles = [];
  90. let activeCircle = null;
  91.  
  92. let getActiveCircle = function(){
  93.   let highest = 0;
  94.   let ind = 0;
  95.   for(let i=0;i<circles.length;i++){
  96.     let c = circles[i];
  97.     let v = checkVisible(c.parent);
  98.     if(v>highest && !c.full){
  99.       highest = v;
  100.       ind = i;
  101.       if(highest==1){
  102.         activeCircle=c;
  103.         return;
  104.       }
  105.     }
  106.   }
  107.   activeCircle = circles[ind];
  108. }
  109.  
  110. let createCircles = function(){
  111.   threads = document.getElementById("posts").children;
  112.   for(let i=1;i<threads.length;i+=2){
  113.     threads[(i-1)/2] = threads[i];
  114.     let c = new viewCircle(threads[i],window.location.href.match(validBoards)[1],(i-1)/2);
  115.     circles[(i-1)/2] = c;
  116.     threads[i] = null;
  117.   }
  118.   getActiveCircle();
  119. }
  120.  
  121. let achievements = {};
  122.  
  123. let getAchievements = async()=>{
  124.   achievements.master = new achieve(2,
  125.                                     "A MASTER",
  126.                                     "Install the <a href='https://pastebin.com/XHn7CKq5'>Master Script</a> and visit the <a href='https://dollars-bbs.org/settings'>settings page</a>.",
  127.                                     await GM.getValue("bbsidle.achievements.master",false),
  128.                                     "if(window.location.href.match(/https:\\\/\\\/dollars-bbs.org\\\/settings/) && document.getElementById('pagemenu'))obtainAchieve('master');");
  129.  
  130.   achievements.home = new achieve(4,
  131.                                   "COMING HOME",
  132.                                   "Activate the Home board and <a href='https://dollars-bbs.org/home'>visit it</a>. (Requires A MASTER)",
  133.                                   await GM.getValue("bbsidle.achievements.home",false),
  134.                                   "if(window.location.href.match(/https:\\\/\\\/dollars-bbs.org\\\/home/) && document.getElementById('pagemenu') && achievements.master.obtained)obtainAchieve('home');");
  135.  
  136.  
  137.   achievements.chat = new achieve(4,
  138.                                   "NOSTALGIA",
  139.                                   "Activate the chat script and click the chatroom button. (Requires A MASTER)",
  140.                                   await GM.getValue("bbsidle.achievements.chat",false),
  141.                                   "function chatAchieve(){"+
  142.                                   "  let e = document.getElementsByTagName('li');"+
  143.                                   "  if(!e.length){"+
  144.                                   "    setTimeout(chatAchieve,1000);"+
  145.                                   "    return;"+
  146.                                   "  }"+
  147.                                   "  e = e[2];"+
  148.                                   "  if(e.children[0].href.match(/https:\\\/\\\/dollars-bbs.org\\\/chatroom/) && achievements.master.obtained)"+
  149.                                   "    e.addEventListener('click',()=>{obtainAchieve('chat');});"+
  150.                                   "}"+
  151.                                   "chatAchieve();");
  152.  
  153.  
  154.   achievements.user = new achieve(10,
  155.                                   "BABY I'M HOME",
  156.                                   "Post in a thread from the Home board. (Requires COMING HOME)",
  157.                                   await GM.getValue("bbsidle.achievements.user",false),
  158.                                   "function userAchieve(){"+
  159.                                   "  if(window.location.href.match(/https:\\\/\\\/dollars-bbs.org\\\/home/) && achievements.home.obtained){"+
  160.                                   "    let bs = document.getElementsByTagName('input');"+
  161.                                   "    if(bs.length<40){"+
  162.                                   "      setTimeout(userAchieve,1000);"+
  163.                                   "      return;"+
  164.                                   "    }"+
  165.                                   "    for(let i=0;i<bs.length;i++){"+
  166.                                   "      if(bs[i].value=='Reply')"+
  167.                                   "        bs[i].addEventListener('click',()=>{obtainAchieve('user')});"+
  168.                                   "    }"+
  169.                                   "  }"+
  170.                                   "}"+
  171.                                   "userAchieve();");
  172.  
  173.  
  174.   achievements.RTT = new achieve(14,
  175.                                  "REGULAR",
  176.                                  "Post in the RTT on 14 different days.",
  177.                                  await GM.getValue("bbsidle.achievements.RTT",false),
  178.                                  "async function incrementRTT(){"+
  179.                                  "  if(parseInt(await GM.getValue('bbsidle.RTTLastDay',0))<=new Date*1-dayInterval){"+
  180.                                  "    let days = parseInt(await GM.getValue('bbsidle.counters.RTTDays'))+1;"+
  181.                                  "    GM.setValue('bbsidle.counters.RTTDays',days);"+
  182.                                  "    GM.setValue('bbsidle.RTTLastDay',new Date()*1);"+
  183.                                  "    if(days>=14)"+
  184.                                  "      obtainAchieve('RTT');"+
  185.                                  "  }"+
  186.                                  "}"+
  187.                                  "function RTTAchieve(){"+
  188.                                  "  let posts = document.getElementsByClassName('thread');"+
  189.                                  "  if(!posts.length){"+
  190.                                  "    setTimeout(RTTAchieve,1000);"+
  191.                                  "    return;"+
  192.                                  "  }"+
  193.                                  "  for(let i=0;i<posts.length;i++){"+
  194.                                  "    if(posts[i].children[0].innerHTML.match(/Random Thought Thread|RTT|Random Though Thread/))"+
  195.                                  "      posts[i].getElementsByTagName('input')[4].addEventListener('click',()=>{incrementRTT();});"+
  196.                                  "  }"+
  197.                                  "}"+
  198.                                  "RTTAchieve();");
  199.  
  200.   achievements.seasoned = new achieve(8,
  201.                                       "SEASONED",
  202.                                       "Reach season 8.",
  203.                                       await GM.getValue("bbsidle.achievements.seasoned",false),
  204.                                       "if(season==8)obtainAchieve('seasoned');");
  205.  
  206.   achievements.lucky = new achieve(7.77,
  207.                                    "LUCKY",
  208.                                    "Get lucky.",
  209.                                    await GM.getValue("bbsidle.achievements.lucky",false),
  210.                                    "if(Math.random()==0)obtainAchieve('lucky');");
  211.  
  212.   achievements.nut = new achieve(1.5,
  213.                                  "NUT",
  214.                                  "Nut.",
  215.                                  await GM.getValue("bbsidle.achievements.nut",false),
  216.                                  "function nutAchieve(){"+
  217.                                  "  if(window.location.href.match(/https:\\\/\\\/dollars-bbs.org\\\/idle/)){"+
  218.                                  "    let textArea = document.getElementById('textArea');"+
  219.                                  "    if(!textArea){"+
  220.                                  "      textArea = document.createElement(\"textarea\");"+
  221.                                  "      textArea.id = 'textArea';"+
  222.                                  "      textArea.style.display = 'none';"+
  223.                                  "      document.body.appendChild(textArea);"+
  224.                                  "      document.addEventListener('keydown',(e)=>{textArea.value+=e.key;});"+
  225.                                  "    }"+
  226.                                  "    if(textArea.value.length>=3)"+
  227.                                  "      textArea.value = textArea.value.substring(textArea.value.length-3);"+
  228.                                  "    if(textArea.value=='nut')"+
  229.                                  "      obtainAchieve('nut');"+
  230.                                  "    else"+
  231.                                  "      setTimeout(nutAchieve,100);"+
  232.                                  "  }"+
  233.                                  "}"+
  234.                                  "nutAchieve();");
  235.   if(prestiges.scriptDev){
  236.     let keys = Object.keys(achievements);
  237.     for(let i=0;i<keys.length;i++){
  238.       let a = achievements[keys[i]];
  239.       if(!a.obtained)
  240.         testAchieve(a);
  241.     }
  242.   }
  243. }
  244.  
  245. let testAchieve = async(achievement)=>{
  246.   eval(achievement.test);
  247. }
  248.  
  249. let obtainAchieve = function(name){
  250.   GM.setValue("bbsidle.achievements."+name,true);
  251.   GM.setValue("bbsidle.upgradeSinceLoad","true");
  252.   toast(achievements[name]);
  253. }
  254.  
  255. let toast = function(a){
  256.   let t = document.createElement("div");
  257.   t.style.cssText = "position:fixed;right:1px;bottom:1px;border:2px solid #EEEEEE;width:250px;line-height:20px;text-align:center;background:#4D4D4D;"
  258.   t.style.borderRadius = "6px";
  259.   document.body.appendChild(t);
  260.   let name = document.createElement("div");
  261.   name.innerHTML = a.name;
  262.   t.appendChild(name);
  263.   let description = document.createElement("div");
  264.   description.innerHTML = a.description;
  265.   t.appendChild(description);
  266.   setTimeout(remove,10000,t);
  267. }
  268.  
  269. let remove = function(e){
  270.   e.parentNode.removeChild(e);
  271. }
  272.  
  273. let achieve = function(mult,nam,desc,obt,tes){
  274.   this.multiplier = mult;
  275.   this.name = nam;
  276.   this.description = desc;
  277.   this.obtained = obt;
  278.   this.test = tes;
  279. }
  280.  
  281. let prestiges = {};
  282. let season = 1;
  283.  
  284. let getPrestiges = async()=>{
  285.   season = parseInt(await GM.getValue("bbsidle.season",1));
  286.   prestiges.keyNumber = 11;
  287.   prestiges.prestiges = 7;
  288.   prestiges.activePrestiges = 1;
  289.   prestiges.seasonRequirements = {};
  290.  
  291.   prestiges.RTT = (await GM.getValue("bbsidle.prestiges.RTT",false));
  292.   prestiges.seasonRequirements.RTT = 2;
  293.   prestiges.activePrestiges+=prestiges.RTT?1:0;
  294.  
  295.   prestiges.scriptDev = (await GM.getValue("bbsidle.prestiges.scriptDev",false));
  296.   prestiges.seasonRequirements.scriptDev = 3;
  297.   prestiges.activePrestiges+=prestiges.scriptDev?1:0;
  298.  
  299.   prestiges.chat = (await GM.getValue("bbsidle.prestiges.chat",false));
  300.   prestiges.seasonRequirements.chat = 4;
  301.   prestiges.activePrestiges+=prestiges.chat?1:0;
  302.  
  303.   prestiges.home = (await GM.getValue("bbsidle.prestiges.home",false));
  304.   prestiges.seasonRequirements.home = 4;
  305.   prestiges.activePrestiges+=prestiges.home?1:0;
  306.  
  307.   prestiges.communalRituals = (await GM.getValue("bbsidle.prestiges.communalRituals",false));
  308.   prestiges.seasonRequirements.communalRituals = 4;
  309.   prestiges.activePrestiges+=prestiges.communalRituals?1:0;
  310.  
  311.   prestiges.threadActivity = (await GM.getValue("bbsidle.prestiges.threadActivity",false));
  312.   prestiges.seasonRequirements.threadActivity = 4;
  313.   prestiges.activePrestiges+=prestiges.threadActivity?1:0;
  314.  
  315.   prestiges.idleGame = (await GM.getValue("bbsidle.prestiges.idleGame",false));
  316.   prestiges.seasonRequirements.idleGame = 8;
  317.   prestiges.activePrestiges+=prestiges.idleGame?1:0;
  318.  
  319.   await getAchievements();
  320.   await getUpgrades();
  321. }
  322.  
  323. let upgrades = {};
  324.  
  325. let getUpgrades = async()=>{
  326.   upgrades.keyNumber = 12;
  327.   upgrades.upgrades = 5;
  328.   upgrades.totalUpgradeLevel = 0;
  329.   upgrades.costs = {};
  330.   upgrades.maxes = {};
  331.   upgrades.requirements = {};
  332.   upgrades.initials = {};
  333.  
  334.   upgrades.multThreads = parseInt(await GM.getValue("bbsidle.upgrades.multThreads",0));
  335.   upgrades.costs.multThreads = "Math.pow(10,21)*Math.pow(12,upgrades.multThreads+1)";
  336.   upgrades.maxes.multThreads = 10;
  337.   upgrades.requirements.multThreads = "let t = upgrades.thread>=50; upgrades.thread = t?2:upgrades.thread; GM.setValue('bbsidle.upgrades.thread',2);return t;";
  338.   upgrades.initials.multThreads = 0;
  339.   upgrades.totalUpgradeLevel+=upgrades.multThreads-upgrades.initials.multThreads;
  340.  
  341.   upgrades.board = parseInt(await GM.getValue("bbsidle.upgrades.board",5));
  342.   upgrades.costs.board = "(40*upgrades.board+5*Math.pow(upgrades.board,Math.log(upgrades.board*Math.log(upgrades.board)/Math.log(1.5))/Math.log(2)))*(1+Math.pow(upgrades.board/10,10))";
  343.   upgrades.initials.board = 5;
  344.   upgrades.totalUpgradeLevel+=upgrades.board-upgrades.initials.board;
  345.  
  346.   upgrades.thread = parseInt(await GM.getValue("bbsidle.upgrades.thread",2));
  347.   upgrades.costs.thread = "10*(10*upgrades.thread+Math.pow(upgrades.thread,Math.log(upgrades.thread)/Math.log(2)+upgrades.multThreads+2.8))*Math.pow(upgrades.multThreads+1,3)*(1+Math.pow(upgrades.thread/10,10))";
  348.   upgrades.maxes.thread = 35+15*season;
  349.   upgrades.initials.thread = 2;
  350.   upgrades.totalUpgradeLevel+=upgrades.thread-upgrades.initials.thread;
  351.  
  352.   upgrades.RTT = parseInt(await GM.getValue("bbsidle.upgrades.RTT",5));
  353.   upgrades.costs.RTT = "5000*(upgrades.RTT+upgrades.RTT*upgrades.RTT)*(1+Math.pow(upgrades.RTT/10,2.5))";
  354.   upgrades.initials.RTT = 5;
  355.   upgrades.totalUpgradeLevel+=upgrades.RTT-upgrades.initials.RTT;
  356.  
  357.   upgrades.introd = parseInt(await GM.getValue("bbsidle.upgrades.introd",4));
  358.   upgrades.costs.introd = "1000*(upgrades.introd+Math.pow(upgrades.introd,2.375))*(1+Math.pow(upgrades.introd/10,2.5))";
  359.   upgrades.initials.introd = 4;
  360.   upgrades.totalUpgradeLevel+=upgrades.introd-upgrades.initials.introd;
  361.  
  362.   calculateMultiplier();
  363. }
  364.  
  365. let multiplier = 1;
  366. let multSet = false;
  367. let multData = {};
  368.  
  369. let calculateMultiplier = async()=>{
  370.   let now = new Date();
  371.   let boardBonus = 1;
  372.   for(let i=0;i<boardsArray.length;i++){
  373.     let b = boardsArray[i];
  374.     let bb = 1;
  375.     let seen = multData[b]?multData[b].seen:parseInt(await GM.getValue("bbsidle."+b+".seen",0));
  376.     if(!multData[b]){
  377.       multData[b] = {};
  378.       multData[b].seen = seen;
  379.     }
  380.     if(now*1-seen<dayInterval){
  381.       bb+=0.01*upgrades.board;
  382.       let bbm = 1;
  383.       for(let j=0;j<10;j++){
  384.         let threadSeen = multData[b][j]?multData[b][j]:parseInt(await GM.getValue("bbsidle."+b+"."+j,0));
  385.         if(!multData[b][j])
  386.           multData[b][j] = threadSeen;
  387.         if(now*1-threadSeen<dayInterval){
  388.           if(upgrades.multThreads>j)
  389.             bbm*=1.05+0.05*Math.log(upgrades.thread)/Math.log(2);
  390.           else
  391.             bb+=upgrades.thread/300;
  392.           if(j==0 && prestiges.home)
  393.             bbm*=1.1;
  394.           if(prestiges.threadActivity)
  395.             bb+=Math.min(0.015,Math.max(0.0005,(0.015+81/99000)/12*(23-(now*1-threadSeen)/(60*60*1000))-81/99000));
  396.         }
  397.       }
  398.       bb*=bbm;
  399.     }
  400.     boardBonus*=bb;
  401.   }
  402.   let RTTBonus = 1;
  403.   let RTTTimeBonus = 1;
  404.   let RTTposted = multData.rtt?multData.rtt:parseInt(await GM.getValue("bbsidle.RTT.posted",0));
  405.   if(!multData.rtt)
  406.     multData.rtt = RTTposted;
  407.   if(now*1-RTTposted<dayInterval){
  408.     RTTBonus = upgrades.RTT;
  409.     if(prestiges.RTT)
  410.       RTTTimeBonus = Math.min(20,Math.max(0.2,21.6/12*(23-(now*1-RTTposted)/(60*60*1000))-1.6));
  411.   }
  412.  
  413.   let introdBonus = multData.introd?multData.introd:await GM.getValue("bbsidle.intro.posted",false);
  414.   if(!multData.introd)
  415.     multData.introd = introdBonus;
  416.   introdBonus = introdBonus?upgrades.introd*2.5:1;
  417.  
  418.   let achievementBonus = multData.achievements?multData.achievements:1;
  419.   if(!multData.achievements){
  420.     let achieves = Object.keys(achievements);
  421.     for(let i=0;i<achieves.length;i++){
  422.       let a = achieves[i];
  423.       if(achievements[a].obtained)
  424.         achievementBonus*=achievements[a].multiplier;
  425.     }
  426.     multData.achievements = achievementBonus;
  427.   }
  428.  
  429.   multiplier = boardBonus*RTTBonus*introdBonus*RTTTimeBonus*achievementBonus/(prestiges.idleGame?Math.max(1,1000*Math.log(money)/Math.log(10)):1);
  430.   for(let i=1;i<season;i++){
  431.     multiplier/=Math.max(1,Math.log(multiplier)/Math.log(100));
  432.   }
  433.   multSet = true;
  434.   memberCount.element.setAttribute("title","The current member count in BBSIdle.\n\nCurrent members per second: "+multiplier.toFixed(3)/tickDiv+"\n\nClick for more information.");
  435. }
  436.  
  437.  
  438. let addListeners = function(){
  439.   let forms = document.getElementsByTagName("form");
  440.   for(let i=0;i<forms.length;i++){
  441.     let f=forms[i];
  442.     f.addEventListener("submit",()=>{
  443.       if(f.id!="threadform"){
  444.         let t = f;
  445.         while(t.parentNode.id!="posts"){
  446.           t = t.parentNode;
  447.         }
  448.         let name = t.children[0].children[0].innerHTML;
  449.         if(name.match(/(RTT|Random Thought Thread|Random Though Thread)/)){
  450.           GM.setValue("bbsidle.RTT.posted",new Date()*1);
  451.           calculateMultiplier();
  452.         }
  453.       }else if(window.location.href.match(/\/intro/)){
  454.         GM.setValue("bbsidle.intro.posted",1);
  455.         calculateMultiplier();
  456.       }
  457.     });
  458.   }
  459. }
  460.  
  461. let forceSaveMoney = false;
  462.  
  463. let buyUpgrade = function(up,all=false){
  464.   if(upgrades.hasOwnProperty(up)){
  465.     let c = eval(upgrades.costs[up])
  466.     c*=prestiges.communalRituals?10:1;
  467.     if(money>=c){
  468.       if(upgrades.maxes[up])
  469.         if(upgrades.maxes[up]<=upgrades[up])
  470.           return false;
  471.       if(upgrades.requirements[up])
  472.         if(!(()=>{eval(upgrades.requirements[up]);}))
  473.           return false;
  474.       upgrades[up]++;
  475.       money-=prestiges.communalRituals?0:c;
  476.       c = eval(upgrades.costs[up]);
  477.       for(let i=0;i<100000 && all && money>=c;i++){
  478.         upgrades[up]++;
  479.         money-=prestiges.communalRituals?0:c;
  480.         c = eval(upgrades.costs[up]);
  481.       }
  482.       forceSaveMoney = true;
  483.       multSet = false;
  484.       GM.setValue("bbsidle.upgrades."+up,upgrades[up]).then(()=>{
  485.         getUpgrades();
  486.         save();
  487.       });
  488.       return true;
  489.     }
  490.   }
  491. }
  492.  
  493. let accTick = new Date()*1;
  494. let money = 0;
  495. let tickDiv = 100;
  496.  
  497. let accumulate = async()=>{
  498.   if(!multSet)
  499.     return;
  500.   if(await GM.getValue("bbsidle.upgradeSinceLoad",false)=="true"){
  501.     load();
  502.     multSet = false;
  503.     return;
  504.   }
  505.   await calculateMultiplier();
  506.   let dt = new Date*1-accTick;
  507.   accTick+=dt;
  508.   dt/=1000*tickDiv;
  509.   money+=dt*multiplier;
  510.  
  511.   if(prestiges.chat)
  512.     money+=upgrades.totalUpgradeLevel*(money/(Math.log(money+2)/Math.log(1.0001)))*dt;
  513.  
  514.   if(prestiges.idleGame){
  515.     let calc = false;
  516.     calc == calc || buyUpgrade("thread",true);
  517.     calc == calc || buyUpgrade("multThreads",true);
  518.     calc == calc || buyUpgrade("board",true);
  519.     calc == calc || buyUpgrade("RTT",true);
  520.     calc == calc || buyUpgrade("introd",true);
  521.     if(calc){
  522.       GM.setValue("bbsidle.upgradeSinceLoad","true");
  523.     }
  524.   }
  525.  
  526.   memberCount.update();
  527. }
  528.  
  529. let save = async()=>{
  530.   GM.setValue("bbsidle.money",forceSaveMoney?money:Math.max(money,parseInt(await GM.getValue("bbsidle.money",0))));
  531.   let keys = Object.keys(upgrades);
  532.   for(let i=0;i<keys.length;i++){
  533.     let k = keys[i];
  534.     GM.setValue("bbsidle.upgrades."+k,forceSaveMoney?upgrades[k]:Math.max(upgrades[k],parseInt(await GM.getValue("bbsidle.upgrades."+k,0))));
  535.   }
  536.   if(forceSaveMoney){
  537.     GM.setValue("bbsidle.upgradeSinceLoad","true");
  538.     forceSaveMoney = false;
  539.   }
  540. }
  541.  
  542. let load = function(){
  543.   getPrestiges();
  544.   GM.getValue("bbsidle.money",0).then((m)=>{money = m;});
  545.   setTimeout(loaded,3000);
  546. }
  547.  
  548. let loaded = function(){
  549.   GM.setValue("bbsidle.upgradeSinceLoad",false);
  550. }
  551.  
  552. let memberCount = {
  553.   element: document.createElement("div"),
  554.   span: document.createElement("span"),
  555.   init: function(){
  556.     document.body.children[0].after(memberCount.element);
  557.     memberCount.element.id = "membercount";
  558.     memberCount.element.style.width = "auto";
  559.     memberCount.element.appendChild(memberCount.span);
  560.     memberCount.element.setAttribute("title","The current member count in BBSIdle.\n\nCurrent members per second: "+multiplier.toFixed(3)/tickDiv+"\n\nClick for more information.");
  561.     memberCount.span.addEventListener("click",()=>{
  562.       window.open("https://dollars-bbs.org/idle","_blank");
  563.     });
  564.     let e = document.createElement("div");
  565.     memberCount.element.prepend(e);
  566.     e.style.cssText = "background:repeating-linear-gradient(90deg, #000000 0px, #000000 calc(120px / 10),#EEEEEE calc(120px / 10), #EEEEEE calc(1373px / 100)); background-position:0px 0px; height:21px; width:calc(100% - 1400px / 100); position:absolute; z-index:-10; margin-left:9px;";
  567.     memberCount.update();
  568.   },
  569.   update: function(){
  570.     memberCount.span.innerHTML = Math.floor(money);
  571.   }
  572. }
  573.  
  574. let idlePage = async()=>{
  575.   document.body.innerHTML = "";
  576.   document.body.style.cssText = "width:100%;height:100%;margin:0px;padding:0px;background:#000000;color:#FFFFFF;font-family:Tahoma;";
  577.   document.title = "BBSIdle";
  578.   if(!multSet){
  579.     setTimeout(idlePage,100);
  580.     document.body.innerHTML = "Loading...";
  581.     return;
  582.   }
  583.  
  584.   let basePlateCss = "background:#4D4D4D;border:1px solid #EEEEEE;padding-left:1.5px;width:741;position:absolute;left:50%;transform:translateX(-50%);";
  585.   let size = 25;
  586.   let today = new Date()*1;
  587.  
  588.   let totalTop = renderOrbs(basePlateCss,size,today);
  589.   setTimeout(renderOrbs,60000,basePlateCss,size);
  590.  
  591.   let upgradeHeight = 47;
  592.   totalTop = renderUpgrades(basePlateCss,totalTop,upgradeHeight);
  593.  
  594.   totalTop = renderPrestiges(basePlateCss,totalTop,upgradeHeight);
  595.  
  596.   let empty = document.createElement("div");
  597.   empty.style.height = "calc(45% + "+totalTop+"px)";
  598.   document.body.appendChild(empty);
  599.  
  600.   if(prestiges.scriptDev)
  601.     renderAchievements();
  602.  
  603.   let reset = document.createElement("div");
  604.   reset.style.cssText = basePlateCss;
  605.   reset.style.lineHeight = "40px";
  606.   reset.style.textAlign = "center";
  607.   reset.style.position = "relative";
  608.   reset.style.left = "37px";
  609.   reset.style.width = "70px";
  610.   reset.style.bottom = "2px";
  611.   reset.innerHTML = "RESET";
  612.   reset.title = "Resets member count and all upgrades. Non-reversible.";
  613.   reset.addEventListener("click",()=>{
  614.     if(confirm("THIS CANNOT BE UNDONE!\n\nContinue, anyway?")){
  615.       GM.setValue("bbsidle.season",1);
  616.       GM.setValue("bbsidle.money",0);
  617.       GM.setValue("bbsidle.upgrades.multThreads",0);
  618.       GM.setValue("bbsidle.upgrades.board",5);
  619.       GM.setValue("bbsidle.upgrades.thread",2);
  620.       GM.setValue("bbsidle.upgrades.RTT",5);
  621.       GM.setValue("bbsidle.upgrades.introd",4);
  622.       GM.setValue("bbsidle.prestiges.RTT",false);
  623.       GM.setValue("bbsidle.prestiges.chat",false);
  624.       GM.setValue("bbsidle.prestiges.scriptDev",false);
  625.       GM.setValue("bbsidle.prestiges.home",false);
  626.       GM.setValue("bbsidle.prestiges.communalRituals",false);
  627.       GM.setValue("bbsidle.prestiges.threadActivity",false);
  628.       GM.setValue("bbsidle.prestiges.idleGame",false);
  629.       GM.setValue("bbsidle.achievements.RTT",false);
  630.       GM.setValue("bbsidle.achievements.master",false);
  631.       GM.setValue("bbsidle.achievements.chat",false);
  632.       GM.setValue("bbsidle.achievements.home",false);
  633.       GM.setValue("bbsidle.achievements.user",false);
  634.       GM.setValue("bbsidle.achievements.nut",false);
  635.       GM.setValue("bbsidle.achievements.seasoned",false);
  636.       GM.setValue("bbsidle.achievements.lucky",false);
  637.       GM.setValue("bbsidle.upgradeSinceLoad","true");
  638.       window.location.reload();
  639.     }
  640.   });
  641.   document.body.appendChild(reset);
  642. }
  643.  
  644. let renderAchievements = function(){
  645.   let achieves = document.createElement("div");
  646.   achieves.style.cssText = "width:300px;height:100%;left:calc(100% - 15px);line-height:"+window.innerHeight+"px;position:fixed;border:1px solid #EEEEEE;background:#181818;top:-1px;";
  647.   achieves.innerHTML = String.fromCharCode(11207);
  648.   achieves.id = "achieves1";
  649.   achieves.addEventListener("click",()=>{
  650.     achieves.innerHTML = (achieves.id=="achieves1"?String.fromCharCode(11208):String.fromCharCode(11207))+achieves.innerHTML.substring(1);
  651.     achieves.style.left = "calc(100% - "+(achieves.id=="achieves1"?300:15)+"px";
  652.     achieves.id = "achieves"+(achieves.id=="achieves1"?2:1);
  653.   });
  654.   document.body.appendChild(achieves);
  655.  
  656.   let holder = document.createElement("div");
  657.   holder.style.cssText = "position:absolute;top:0px;left:0px;width:100%;height:100%;overflow-y:auto;overflow-x:hidden;";
  658.   achieves.appendChild(holder);
  659.  
  660.   let keys = Object.keys(achievements);
  661.   for(let i=0;i<keys.length;i++){
  662.     let a = achievements[keys[i]];
  663.     let achieve = document.createElement("div");
  664.     achieve.style.cssText = "position:relative;left:17px;top:"+(2+2*i)+"px;border:1px solid #EEEEEE;width:270px;line-height:20px;text-align:center;background:#4D4D4D;padding-bottom:2px;";
  665.     achieve.style.borderRadius = "6px";
  666.     achieve.title = "Multiplier: "+a.multiplier;
  667.     holder.appendChild(achieve);
  668.     let name = document.createElement("div");
  669.     name.style.color = a.obtained?"#FFEF4B":"#EEEEEE";
  670.     name.innerHTML = a.name;
  671.     achieve.appendChild(name);
  672.     let description = document.createElement("div");
  673.     description.innerHTML = a.description;
  674.     achieve.appendChild(description);
  675.   }
  676. }
  677.  
  678. let renderUpgrades = function(basePlateCss,totalTop,upgradeHeight){
  679.   let info = document.createElement("div");
  680.   info.style.cssText = basePlateCss;
  681.   info.style.border = "2px solid #EEEEEE";
  682.   info.style.borderRadius = "6px";
  683.   info.style.top = totalTop+"px";
  684.   info.style.padding = "10px 25px 25px 45px";
  685.   info.style.fontSize = "14px";
  686.   info.style.width = "672.5px";
  687.   info.style.background = "#181818";
  688.   info.style.height = (443+47*upgrades.upgrades+19)+"px";
  689.   info.innerHTML = '<div style="display:inline-block;position:relative;"><b>1</b> Name: <span style="font-size:16px;"><b>Name</b> <i>!Lup0uZudWo</i></span> : 2022-02-25 01:54 ID:7Yb3yRbC [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  690.     "WHAT IS THIS? This is BBSIdle, an idle game made by Name. The idea did not come from a search for a way to make people interact with the BBS, that was just a happy accident.<br><br>"+
  691.     "The bars above can be hovered, showing that they are boards of the BBS. Each circle is a thread.<br>"+
  692.     "Boards you've visited in the last 23 hours are in green. Threads you've seen for over 20 seconds are also green, with the percentage of green indicating how long until that thread no longer counts as seen.<br><br>"+
  693.     "Your goal is to get as many (fake) members as possible. You get them by having any page of the BBS open. No, you cannot see the member count here. Go actually interact with the BBS you dingopolous.<br><br>"+
  694.     "Standard idle game stuff applies. Below are upgrades. You can <span style='text-decoration:line-through'>sacrifice</span> make old members leave to get those upgrades to more quickly accumulate new members.<br><br>"+
  695.     "At base, you obtain one member every 100 seconds. Each board you've visited in the last 23 hours multiplies the number of members gained in that time by 1.05, with each thread seen on that board adding 0.006666... to that multiplier. Individual board multipliers are multiplicative with each other. Upgrades can increase all beneficial numbers mentioned.<br><br>"+
  696.     "Additionally, you get a 5 times boost to member generation for 23 hours when you post in the RTT, and a permanent 10 times boost if you post a new thread on the Introductions board. These boosts are multiplicative with everything else, but you can only have one of each active at any one time. No spamming to get super member boosts.<br><br>"+
  697.     "Upgrades below, hovering them will explain what they do.";
  698.   totalTop+=485;
  699.   document.body.appendChild(info);
  700.  
  701.   new upgradeDiv(totalTop,
  702.                  "BETTER BOARD MODERATION",
  703.                  "Increases the base multiplier for active boards by 0.01\n\nCost: "+Math.ceil(eval(upgrades.costs.board))+" members\nCurrent level: "+(upgrades.board-upgrades.initials.board)+"\nMax level: infinite",
  704.                  "board");
  705.   totalTop+=upgradeHeight;
  706.  
  707.   new upgradeDiv(totalTop,
  708.                  "MORE ENGAGING THREADS",
  709.                  "Increases the base multiplier for active threads by 1/300 (0.00333...)\n\nCost: "+Math.ceil(eval(upgrades.costs.thread))+" members\nCurrent level: "+(upgrades.thread-upgrades.initials.thread)+"\nMax level: 50",
  710.                  "thread",
  711.                  upgrades.maxes.thread);
  712.   totalTop+=upgradeHeight;
  713.  
  714.   new upgradeDiv(totalTop,
  715.                  "MORE ACTIVE RTT",
  716.                  "Increases the base multiplier for the RTT by 1\n\nCost: "+Math.ceil(eval(upgrades.costs.RTT))+" members\nCurrent level: "+(upgrades.RTT-upgrades.initials.RTT)+"\nMax level: infinite",
  717.                  "RTT",0,true);
  718.   totalTop+=upgradeHeight;
  719.  
  720.   new upgradeDiv(totalTop,
  721.                  "INTRODUCTION ONE-UPSMANSHIP",
  722.                  "Increases the base multiplier for your intro by 2.5\n\nCost: "+Math.ceil(eval(upgrades.costs.introd))+" members\nCurrent level: "+(upgrades.introd-upgrades.initials.introd)+"\nMax level: infinite",
  723.                  "introd",0,true);
  724.   totalTop+=upgradeHeight;
  725.  
  726.   new upgradeDiv(totalTop,
  727.                  "THREAD GUIDELINE REFORMATION",
  728.                  "Increases the base multiplier for a number of active threads to 1.05+0.05*log_2(thread engagement level) and makes it multiplicative with the board multiplier\nAdditionally changes the active thread color from green to gold\n\nCost: "+Math.ceil(eval(upgrades.costs.multThreads))+" members\nCurrent level: "+(upgrades.multThreads-upgrades.initials.multThreads)+"\nMax level: 10\nRequires 50 levels of MORE ENGAGING THREADS\nResets that upgrade to 2 upon purchase",
  729.                  "multThreads",
  730.                  upgrades.maxes.multThreads);
  731.   totalTop+=upgradeHeight;
  732.  
  733.   totalTop+=21;
  734.  
  735.   return totalTop;
  736. }
  737.  
  738. let renderPrestiges = function(basePlateCss,totalTop,upgradeHeight){
  739.   if(upgrades.thread == upgrades.maxes.thread && upgrades.multThreads == upgrades.maxes.multThreads && season<8){
  740.     let prestigeButton = document.createElement("div");
  741.     prestigeButton.style.cssText = basePlateCss;
  742.     prestigeButton.style.borderRadius = "6px";
  743.     prestigeButton.style.textAlign = "center";
  744.     prestigeButton.style.lineHeight = "40px";
  745.     prestigeButton.style.cursor = "pointer";
  746.     prestigeButton.style.top = totalTop+"px";
  747.     prestigeButton.innerHTML = "NEW SEASON OF DURARARA";
  748.     prestigeButton.title = "Resets everything to 0, but grants access to at least one new, free upgrade, up until season 8. Each season also divides your multiplier by log_100(multiplier)"
  749.     document.body.appendChild(prestigeButton);
  750.     totalTop+=upgradeHeight;
  751.    
  752.     prestigeButton.addEventListener("click",()=>{newSeason();});
  753.   }
  754.  
  755.   if(season > 1){
  756.     let t = totalTop;
  757.     let info = document.createElement("div");
  758.     info.style.cssText = basePlateCss;
  759.     info.style.border = "2px solid #EEEEEE";
  760.     info.style.borderRadius = "6px";
  761.     info.style.top = totalTop+"px";
  762.     info.style.padding = "10px 25px 25px 45px";
  763.     info.style.fontSize = "14px";
  764.     info.style.width = "672.5px";
  765.     info.style.background = "#181818";
  766.     info.style.height = (132+19)+"px";
  767.     info.innerHTML = '<div style="display:inline-block;position:relative;"><b>1</b> Name: <span style="font-size:16px;"><b>Name</b> <i>!Lup0uZudWo</i></span> : 2022-03-2 07:54 ID:m6cyPtw8 [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  768.       "8 years have passed since the previous season, the BBS userbase has dwindled to a small handful of users.<br><br>"+
  769.       "Season "+season+" of Durarara has come. The old members won't return, cutting off a percentage of your member gain, but with your knowledge of how the BBS progressed last time, you can make even more engaging threads.<br><br>"+
  770.       "Do try to keep these new members for longer, yeah?";
  771.     totalTop+=177;
  772.     document.body.appendChild(info);
  773.  
  774.     let num = 2;
  775.     let d = new prestigeDiv(totalTop,
  776.                             "HYPERACTIVE RTT",
  777.                             "Multiply your members per second by 0.2 to 20, based on the amount of time until your RTT bonus disappears. Reaches minimum at 1 hour left, starts decrasing after passing 12 hours remaining",
  778.                             "RTT",
  779.                             'Name: <span style="font-size:16px;"><b>Firion</b> <i>!HYDlod9R/I</i></span> : 2022-03-10 10:54 ID:coOTbBKE [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  780.                               "<div style='display:inline-block;position:relative;left:30px;width:601px;'>We need to be posting in the RTT more.</div>",
  781.                             num);
  782.     totalTop+=d.height;
  783.     num+=d.height>47?1:0;
  784.  
  785.     d = new prestigeDiv(totalTop,
  786.                         "USERSCRIPT DEVELOPER",
  787.                         "Unlock achievements",
  788.                         "scriptDev",
  789.                         'Name: <span style="font-size:16px;"><b>Firion</b> <i>!HYDlod9R/I</i></span> : 2022-03-22 01:31 ID:FWyegyR+ [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  790.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'>It's about time we modernize the site!</div>",
  791.                         num);
  792.     totalTop+=d.height;
  793.     num+=d.height>47?1:0;
  794.  
  795.     d = new prestigeDiv(totalTop,
  796.                         "CUSTOM CHAT",
  797.                         "Gain a small percentage of your current members as members per second",
  798.                         "chat",
  799.                         'Name: <span style="font-size:16px;"><b>zengat</b> <i>!!qhsAsehg</i></span> : 2022-04-01 15:00 ID:coOTbBKE [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  800.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'><b>Main is hell, come to IRC for funsies!</b></div>",
  801.                         num);
  802.     totalTop+=d.height;
  803.     num+=d.height>47?1:0;
  804.  
  805.     d = new prestigeDiv(totalTop,
  806.                         "HOME BOARD",
  807.                         "Gives the first thread of each board an additional *1.1 multiplier",
  808.                         "home",
  809.                         'Name: <span style="font-size:16px;"><b>Name</b> <i>!Lup0uZudWo</i></span> : 2022-04-07 06:19 ID:m6cyPtw8 [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  810.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'>Firion asked for Home, zengat gave me the push to make it by saying he'd do it in a way I highly disagreed with.</div>",
  811.                         num);
  812.     totalTop+=d.height;
  813.     num+=d.height>47?1:0;
  814.  
  815.     d = new prestigeDiv(totalTop,
  816.                         "COMMUNAL RITUALS",
  817.                         "Multiply upgrade costs by 10, but buying upgrades no longer reduce your member count",
  818.                         "communalRituals",
  819.                         'Name: <span style="font-size:16px;"><b>undead</b></span> : 2022-04-15 19:09 ID:YYYYYYYY [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  820.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'>Instead of completely sacrificing our members to get better BBS stuff, let's each give up just a small portion of our life force so we can all reap the benefits of the rituals.</div>",
  821.                         num);
  822.     totalTop+=d.height;
  823.     num+=d.height>47?1:0;
  824.    
  825.     d = new prestigeDiv(totalTop,
  826.                         "HYPERACTIVE THREADS",
  827.                         "Gain an additional 0.0005 to 0.015 multiplier per active thread, based on the amount of time until each thread bonus disappears. Reaches minimum at 1 hour left, starts decrasing after passing 12 hours remaining",
  828.                         "threadActivity",
  829.                         'Name: <span style="font-size:16px;"><b>Firion</b> <i>!HYDlod9R/I</i></span> : 2022-04-22 18:22 ID:coOTbBKE [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  830.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'>We need to be the change we want to see in the BBS. Let's actually post some replies.</div>",
  831.                         num);
  832.     totalTop+=d.height;
  833.     num+=d.height>47?1:0;
  834.    
  835.     d = new prestigeDiv(totalTop,
  836.                         "IDLE GAME",
  837.                         "Heavily decrease your members per second, but automatically unlock upgrades.",
  838.                         "idleGame",
  839.                         'Name: <span style="font-size:16px;"><b>Name</b> <i>!Lup0uZudWo</i></span> : 2022-04-07 06:19 ID:m6cyPtw8 [<a href="https://dollars-bbs.org/main" style="color:#EEEEEE;" target="_blank">Del</a>]</div><span style="line-height:10px;"><br><br></span>'+
  840.                           "<div style='display:inline-block;position:relative;left:30px;width:601px;'>I made an idle game based around the BBS. You get more (fake) members the more you interact with the BBS (up to a point, to avoid spam.)</div>",
  841.                         num);
  842.     totalTop+=d.height;
  843.     num+=d.height>47?1:0;
  844.    
  845.     info.style.height = (totalTop-t-39+19)+"px";
  846.  
  847.     totalTop+=19;
  848.    
  849.   }
  850.  
  851.   return totalTop;
  852. }
  853.  
  854. let prestigeDiv = function(top,name,title,prestige,post,number){
  855.   this.height = 0;
  856.   if(prestiges.seasonRequirements[prestige]<=season){
  857.     this.element = document.createElement("div");
  858.     this.element.style.cssText = "background:#4D4D4D;border:1px solid #EEEEEE;padding-left:1.5px;width:671;position:absolute;left:50%;transform:translateX(-50%);"+(prestiges.activePrestiges>=season && !prestiges[prestige]?"color:#DDDDDD;":"");
  859.     this.element.style.borderRadius = "6px";
  860.     this.element.style.top = top+"px";
  861.     document.body.appendChild(this.element);
  862.     if(!prestiges[prestige]){
  863.       this.element.style.textAlign = "center";
  864.       this.element.style.lineHeight = "40px";
  865.       this.element.innerHTML = name;
  866.       this.element.title = title;
  867.       if(prestiges.activePrestiges<season){
  868.         this.element.style.cursor = "pointer";
  869.         this.element.addEventListener("click",async()=>{
  870.           GM.setValue("bbsidle.prestiges."+prestige,true).then(async()=>{
  871.             GM.setValue("bbsidle.upgradeSinceLoad","true").then(()=>{
  872.               window.location.reload();
  873.             });
  874.           });
  875.         });
  876.       }
  877.       this.height = 47;
  878.     }else{
  879.       this.element.style.fontSize = "14px";
  880.       this.element.style.paddingBottom = "25px";
  881.       this.element.innerHTML = "<div style='display:inline-block;position:relative;left:3px;'><b>"+number+"</b> "+post;
  882.       this.height = this.element.offsetHeight+5;
  883.     }
  884.   }
  885. }
  886.  
  887. let renderOrbs = function(basePlateCss,size,today=new Date()*1){
  888.   setTimeout(renderOrbs,60000,basePlateCss,size);
  889.   if(document.getElementById("boardHolder")){
  890.     document.body.removeChild(document.getElementById("boardHolder"));
  891.     document.body.removeChild(document.getElementById("RTTCircle"));
  892.     document.body.removeChild(document.getElementById("introCircle"));
  893.   }
  894.  
  895.   let totalTop = 1;
  896.   let boardHolder = document.createElement("div");
  897.   boardHolder.id = "boardHolder";
  898.   boardHolder.style.cssText = basePlateCss;
  899.   boardHolder.style.borderRadius = "6px";
  900.   boardHolder.style.top = totalTop+"px";
  901.   boardHolder.style.height = "300px";
  902.   totalTop+=307;
  903.   let totalBoardMult = 1;
  904.   document.body.appendChild(boardHolder);
  905.   for(let i=0;i<boardsArray.length;i++){
  906.     let b = boardsArray[i];
  907.     let board = document.createElement("div");
  908.     board.style.cssText = "width:30px;overflow-x:wrap;margin:3px 1.5px;display:inline-block;cursor:pointer;";
  909.     board.style.border = "2px solid #BBBBBB";
  910.     board.style.borderRadius = "6px";
  911.     board.addEventListener("click",()=>{window.open("https://dollars-bbs.org/"+b,"_blank");});
  912.     let boardToday = today-(multData[b]?multData[b].seen:0)<dayInterval;
  913.     let boardMult = 1+(boardToday?0.01*upgrades.board:0);
  914.     board.style.background = boardToday?"#00BB2B":"#BB062B";
  915.     board.setAttribute("title",b);
  916.     boardHolder.appendChild(board);
  917.     let bbm = 1;
  918.     for(let j=0;j<10;j++){
  919.       let threadSeen = multData[b]?(multData[b][j]?multData[b][j]:0):0;
  920.       let threadToday = today-threadSeen<dayInterval;
  921.       let thread = document.createElement("canvas");
  922.       let activeColor = "#00FF4B";
  923.       if(threadToday && boardToday){
  924.         if(upgrades.multThreads>j){
  925.           bbm*=1.05+0.05*Math.log(upgrades.thread)/Math.log(2);
  926.           activeColor = "#FFEF4B";
  927.         }else
  928.           boardMult+=upgrades.thread/300;
  929.         if(j==0 && prestiges.home)
  930.           bbm*=1.1;
  931.         if(prestiges.threadActivity)
  932.           boardMult+=Math.min(0.015,Math.max(0.0005,(0.015+81/99000)/12*(23-(today-threadSeen)/(60*60*1000))-81/99000));
  933.       }
  934.       thread.width = size;
  935.       thread.height = size;
  936.       thread.style.marginLeft = "2.5px";
  937.       let context = thread.getContext("2d");
  938.       context.beginPath();
  939.       context.arc(size/2,size/2,size/2-2,0,2*Math.PI);
  940.       context.lineWidth = 3;
  941.       context.strokeStyle = "#BBBBBB";
  942.       context.stroke();
  943.       context.beginPath();
  944.       context.fillStyle = threadToday?activeColor:"#FF164B";
  945.       context.arc(size/2,size/2,size/2-3,0,2*Math.PI);
  946.       context.fill();
  947.       context.beginPath();
  948.       context.moveTo(size/2,size/2);
  949.       context.lineTo(size/2,3);
  950.       context.arc(size/2,size/2,size/2-3,1.5*Math.PI,1.5*Math.PI+2*Math.PI*(today-threadSeen)/dayInterval);
  951.       context.fillStyle = "#FF164B";
  952.       context.fill();
  953.       board.appendChild(thread);
  954.     }
  955.     boardMult*=bbm;
  956.     totalBoardMult*=boardMult;
  957.     let bm = document.createElement("span");
  958.     board.appendChild(bm);
  959.     bm.style.lineHeight = "18px";
  960.     bm.innerHTML = boardMult.toFixed(2);
  961.     if(bm.innerHTML.length>4)
  962.       bm.style.fontSize = "13px";
  963.   }
  964.   let total = document.createElement("div");
  965.   total.innerHTML = "TOTAL BOARD MULTIPLIER: "+totalBoardMult.toFixed(2);
  966.   boardHolder.appendChild(total);
  967.   total.style.textAlign = "center";
  968.  
  969.   let RTT = document.createElement("div");
  970.   RTT.id = "RTTCircle";
  971.   RTT.innerHTML = "RTT";
  972.   RTT.style.cssText = "text-align:center;position:absolute;top:1px;left:calc(50% + 377px);width:50px;height:50px;line-height:50px;font-family:impact;";
  973.   let orb = document.createElement("canvas");
  974.   RTT.appendChild(orb);
  975.   orb.width = size*2;
  976.   orb.height = size*2;
  977.   orb.style.cssText = "z-index:-10;position:absolute;left:0px;";
  978.   let rttContext = orb.getContext("2d");
  979.   rttContext.beginPath();
  980.   rttContext.arc(size,size,size-2,0,2*Math.PI);
  981.   rttContext.lineWidth = 3;
  982.   rttContext.strokeStyle = "#BBBBBB";
  983.   rttContext.stroke();
  984.   rttContext.beginPath();
  985.   rttContext.fillStyle = today-multData.rtt<dayInterval?"#00FF4B":"#BB062B";
  986.   rttContext.arc(size,size,size-3,0,2*Math.PI);
  987.   rttContext.fill();
  988.   rttContext.beginPath();
  989.   rttContext.moveTo(size,size);
  990.   rttContext.lineTo(size,3);
  991.   rttContext.arc(size,size,size-3,1.5*Math.PI,1.5*Math.PI+2*Math.PI*(today-multData.rtt)/dayInterval);
  992.   rttContext.fillStyle = "#FF164B";
  993.   rttContext.fill();
  994.   document.body.appendChild(RTT);
  995.  
  996.   let intro = document.createElement("div");
  997.   intro.id = "introCircle";
  998.   intro.innerHTML = "INTRO";
  999.   intro.style.cssText = "text-align:center;position:absolute;top:1px;right:calc(50% + 377px);width:50px;height:50px;line-height:50px;font-family:impact;";
  1000.   let intorb = document.createElement("canvas");
  1001.   intro.appendChild(intorb);
  1002.   intorb.width = size*2;
  1003.   intorb.height = size*2;
  1004.   intorb.style.cssText = "z-index:-10;position:absolute;left:0px;";
  1005.   let introContext = intorb.getContext("2d");
  1006.   introContext.beginPath();
  1007.   introContext.arc(size,size,size-2,0,2*Math.PI);
  1008.   introContext.lineWidth = 3;
  1009.   introContext.strokeStyle = "#BBBBBB";
  1010.   introContext.stroke();
  1011.   introContext.beginPath();
  1012.   introContext.fillStyle = multData.introd?"#00FF4B":"#BB062B";
  1013.   introContext.arc(size,size,size-3,0,2*Math.PI);
  1014.   introContext.fill();
  1015.   document.body.appendChild(intro);
  1016.  
  1017.   let achievementsMultiplier = multData.achievements;
  1018.  
  1019.   let multiplierInfo = document.createElement("div");
  1020.   multiplierInfo.style.cssText = basePlateCss;
  1021.   multiplierInfo.style.borderRadius = "6px";
  1022.   multiplierInfo.style.top = totalTop+"px";
  1023.   multiplierInfo.style.textAlign = "center";
  1024.   totalTop+=27;
  1025.   multiplierInfo.innerHTML = "TOTAL MULTIPLIER: <span title='RTT'>"+(today-multData.rtt<dayInterval?upgrades.RTT:1).toFixed(2)+"</span>"+
  1026.                              (prestiges.RTT?" * <span title='Current HYPERACTIVE RTT multiplier (min 0.2 at 1 hour or less left, max 20 at 12 hours or more left)'>"+Math.min(20,Math.max(0.2,21.6/12*(23-(today*1-multData.rtt)/(60*60*1000))-1.6)).toFixed(2)+"</span>":"")+
  1027.                              " * <span title='Intro'>"+(multData.introd?upgrades.introd*2.5:1).toFixed(2)+"</span> * <span title='Boards'>"+totalBoardMult.toFixed(2)+"</span>"+
  1028.                              (prestiges.scriptDev?" * <span title='Total multiplier from achievements'>"+achievementsMultiplier.toFixed(2)+"</span>":"")+
  1029.                              " = "+multiplier.toFixed(2);
  1030.   document.body.appendChild(multiplierInfo);
  1031.  
  1032.   return totalTop;
  1033. }
  1034.  
  1035. let newSeason = async()=>{
  1036.   await GM.setValue("bbsidle.season",season+1);
  1037.   await GM.setValue("bbsidle.money",0);
  1038.   await GM.setValue("bbsidle.upgrades.multThreads",0);
  1039.   await GM.setValue("bbsidle.upgrades.board",5);
  1040.   await GM.setValue("bbsidle.upgrades.thread",2);
  1041.   await GM.setValue("bbsidle.upgrades.RTT",5);
  1042.   await GM.setValue("bbsidle.upgrades.introd",4);
  1043.   await GM.setValue("bbsidle.upgradeSinceLoad","true");
  1044.   window.location.reload();
  1045. }
  1046.  
  1047. let upgradeDiv = function(top,name,title,upgradeName,max=0,buyAll=false){
  1048.   this.upgrade = document.createElement("div");
  1049.   this.upgrade.style.cssText = "background:#4D4D4D;border:1px solid #EEEEEE;padding-left:1.5px;width:671;position:absolute;left:50%;transform:translateX(-50%);cursor:pointer;";
  1050.   this.upgrade.style.borderRadius = "6px";
  1051.   this.upgrade.style.top = top+"px";
  1052.   this.upgrade.style.textAlign = "center";
  1053.   this.upgrade.style.lineHeight = "40px";
  1054.   this.upgrade.innerHTML = name;
  1055.   this.upgrade.title = title;
  1056.   this.cost = document.createElement("div");
  1057.   this.cost.innerHTML = Math.ceil(eval(upgrades.costs[upgradeName])*(prestiges.communalRituals?10:1))+"M";
  1058.   this.level = document.createElement("div");
  1059.   this.level.innerHTML = "LEVEL "+(upgrades[upgradeName]-upgrades.initials[upgradeName])+(max?"/"+(max-upgrades.initials[upgradeName]):"");
  1060.   this.info = document.createElement("div");
  1061.   this.info.style.cssText = "line-height:20px;position:absolute;left:2px;top:0px;width:200px;";
  1062.   this.info.appendChild(this.level);
  1063.   this.info.appendChild(this.cost);
  1064.   this.upgrade.appendChild(this.info);
  1065.   this.buyAll = document.createElement("div");
  1066.   this.buyAll.innerHTML = "BUY ALL";
  1067.   this.buyAll.style.cssText = "background:#777777;border:2px solid #EEEEEE;position:absolute;right:2px;width:70px;line-height:30px;text-align:center;top:3px;";
  1068.   if(buyAll){
  1069.     this.upgrade.appendChild(this.buyAll);
  1070.     this.buyAll.addEventListener("click",()=>{
  1071.       if(buyUpgrade(upgradeName,true)){
  1072.         idlePage();
  1073.       }
  1074.     });
  1075.   }
  1076.   document.body.appendChild(this.upgrade);
  1077.   this.upgrade.addEventListener("click",(e)=>{
  1078.     if(buyUpgrade(upgradeName) && e.target!=this.buyAll){
  1079.       idlePage();
  1080.     }
  1081.   });
  1082. }
  1083.  
  1084. let bbsIdleOnce = false;
  1085.  
  1086. let run = function(){
  1087.   if(!bbsIdleOnce){
  1088.     bbsIdleOnce = true;
  1089.     load();
  1090.   }
  1091.   let cboard = window.location.href.match(validBoards);
  1092.   if(cboard){
  1093.     if(!document.getElementById("posts")){
  1094.       setTimeout(run,100);
  1095.       return;
  1096.     }
  1097.     addListeners();
  1098.     GM.setValue("bbsidle."+cboard[1]+".seen",new Date()*1);
  1099.     createCircles();
  1100.     memberCount.init();
  1101.   }else if(window.location.href.startsWith("https://dollars-bbs.org/idle")){
  1102.     idlePage();
  1103.   }
  1104.   setInterval(accumulate,250);
  1105.   setInterval(save,1000*60);
  1106. }
  1107.  
  1108. setTimeout(run,1000);
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
Add Comment
Please, Sign In to add comment