Torn Extensions - Gym Torn Gain

calculates gym gain based on Vladars calculations

目前为 2024-08-27 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Torn Extensions - Gym Torn Gain
  3. // @namespace TornExtensions
  4. // @version 1.4.6
  5. // @description calculates gym gain based on Vladars calculations
  6. // @author Xradiation
  7. // @match https://www.torn.com/gym.php*
  8. // @grant none
  9. // @require https://code.jquery.com/jquery-3.7.1.slim.min.js
  10. // @run-at document-idle
  11. /* globals jQuery, $, waitForKeyElements */
  12. // ==/UserScript==
  13.  
  14. //you can manually insert an apikey here
  15. var ManualKey = "apikeyhere";
  16.  
  17. function readCookie(variable){
  18. var first = document.cookie.split(variable+'=')[1];
  19. return (typeof first !== 'undefined')? first.split(';')[0]: false;
  20. }
  21.  
  22. function en_de_code(text, key, mode){
  23. var letters = (mode)?'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''):'ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210zyxwvutsrqponmlkjihgfedcba'.split('');
  24. key = (typeof key == 'number')? key.toString():key;
  25. var textArr=text.split('');
  26. var keyArr=key.split('');
  27. var z=0;
  28. let coded =[];
  29. textArr.forEach(function(item){
  30. let indexTemp= letters.indexOf(item) + parseInt(keyArr[z]);
  31. let index= indexTemp-letters.length*parseInt(indexTemp/letters.length);
  32. coded.push(letters[index]);
  33. (z>=(keyArr.length -1))?z=0:z++;
  34. });
  35. return coded.join('');
  36. }
  37. //leave this in global, i am lazy
  38. var playerId = readCookie('uid');
  39.  
  40. (function() {
  41. 'use strict';
  42. //the userscript is currently diabled due to api
  43. if(readCookie('GTGdisabled') == 'true') return;
  44.  
  45. //EDIT AT OWN RISK!!!
  46. manualEstimator();
  47.  
  48. //remove old apikeys if stil there
  49. if(localStorage.apiKey || localStorage.XrayApiKey) {
  50. localStorage.enXrayApiKey = en_de_code((localStorage.XrayApiKey || localStorage.apiKey),readCookie('uid'),0);
  51. localStorage.removeItem("apiKey");
  52. localStorage.removeItem("XrayApiKey");
  53. }
  54.  
  55. if(typeof(ManualKey) != "undefined"&&
  56. ManualKey != "apikeyhere" &&
  57. ManualKey != "" &&
  58. ManualKey != null) localStorage.enXrayApiKey = en_de_code(ManualKey,playerId,0);
  59.  
  60. //minified vars
  61. var Gymlist2=[{Gym:"Premier Fitness",Energy:5,Str:2,Spe:2,Def:2,Dex:2},{Gym:"Average Joes",Energy:5,Str:2.4,Spe:2.4,Def:2.8,Dex:2.4},{Gym:"Woody's Workout",Energy:5,Str:2.8,Spe:3.2,Def:3,Dex:2.8},{Gym:"Beach Bods",Energy:5,Str:3.2,Spe:3.2,Def:3.2,Dex:"0"},{Gym:"Silver Gym",Energy:5,Str:3.4,Spe:3.6,Def:3.4,Dex:3.2},{Gym:"Pour Femme",Energy:5,Str:3.4,Spe:3.6,Def:3.6,Dex:3.8},{Gym:"Davies Den",Energy:5,Str:3.7,Spe:"0",Def:3.7,Dex:3.7},{Gym:"Global Gym",Energy:5,Str:4,Spe:4,Def:4,Dex:4},{Gym:"Knuckle Heads",Energy:10,Str:4.8,Spe:4.4,Def:4,Dex:4.2},{Gym:"Pioneer Fitness",Energy:10,Str:4.4,Spe:4.6,Def:4.8,Dex:4.4},{Gym:"Anabolic Anomalies",Energy:10,Str:5,Spe:4.6,Def:5.2,Dex:4.6},{Gym:"Core",Energy:10,Str:5,Spe:5.2,Def:5,Dex:5},{Gym:"Racing Fitness",Energy:10,Str:5,Spe:5.4,Def:4.8,Dex:5.2},{Gym:"Complete Cardio",Energy:10,Str:5.5,Spe:5.8,Def:5.5,Dex:5.2},{Gym:"Legs Bums and Tums",Energy:10,Str:"0",Spe:5.6,Def:5.6,Dex:5.8},{Gym:"Deep Burn",Energy:10,Str:6,Spe:6,Def:6,Dex:6},{Gym:"Apollo Gym",Energy:10,Str:6,Spe:6.2,Def:6.4,Dex:6.2},{Gym:"Gun Shop",Energy:10,Str:6.6,Spe:6.4,Def:6.2,Dex:6.2},{Gym:"Force Training",Energy:10,Str:6.4,Spe:6.6,Def:6.4,Dex:6.8},{Gym:"Cha Cha's",Energy:10,Str:6.4,Spe:6.4,Def:6.8,Dex:7},{Gym:"Atlas",Energy:10,Str:7,Spe:6.4,Def:6.4,Dex:6.6},{Gym:"Last Round",Energy:10,Str:6.8,Spe:6.6,Def:7,Dex:6.6},{Gym:"The Edge",Energy:10,Str:6.8,Spe:7,Def:7,Dex:6.8},{Gym:"George's",Energy:10,Str:7.3,Spe:7.3,Def:7.3,Dex:7.3},{Gym:"Balboas Gym",Energy:25,Str:"0",Spe:"0",Def:7.5,Dex:7.5},{Gym:"Frontline Fitness",Energy:25,Str:7.5,Spe:7.5,Def:"0",Dex:"0"},{Gym:"Gym 3000",Energy:50,Str:8,Spe:"0",Def:"0",Dex:"0"},{Gym:"Mr. Isoyamas",Energy:50,Str:"0",Spe:"0",Def:8,Dex:"0"},{Gym:"Total Rebound",Energy:50,Str:"0",Spe:8,Def:"0",Dex:"0"},{Gym:"Elites",Energy:50,Str:"0",Spe:"0",Def:"0",Dex:8},{Gym:"Sports Science Lab",Energy:25,Str:9,Spe:9,Def:9,Dex:9}];
  62. var Gym,gymNumber,speed,strength,defense,dexterity,strength_modifier,defense_modifier,speed_modifier,dexterity_modifier,happy,energy,i,n,modifierSpe=1,modifierAll=1,modifierStr=1,modifierDex=1,modifierDef=1,a=3.480061091*Math.pow(10,-7),b=250,c=3.091619094*Math.pow(10,-6),d=6.82775184551527*Math.pow(10,-5),e=-.0301431777;
  63. var apiKey;
  64.  
  65. if (localStorage.enXrayApiKey === null ||
  66. localStorage.enXrayApiKey === undefined ||
  67. localStorage.enXrayApiKey === "") {
  68.  
  69. console.info('api is null');
  70.  
  71. // poppup message to set api key
  72. poppupMesage("Please insert your API key in order to use gymtorngains:", "apikey")
  73.  
  74. } else{
  75. apiKey = en_de_code(window.localStorage.enXrayApiKey,playerId,1);
  76. statsEstimator();
  77. }
  78.  
  79. function statsEstimator() {
  80. if (document.getElementById("gymroot")) {
  81. var urlStats = 'https://api.torn.com/user/?selections=battlestats,gym,bars,perks&key=' + apiKey;
  82. //api call
  83. fetch(urlStats).then(function(response) {
  84. response.json().then(function(data) {
  85. if(data.hasOwnProperty("error")) {
  86. handleErrorCode(data.error);
  87. return;
  88. }
  89. //apiRequest1
  90. console.log(data);
  91. strength = data.strength;
  92. defense = data.defense;
  93. speed = data.speed;
  94. dexterity = data.dexterity;
  95. strength_modifier = data.strength_modifier;
  96. defense_modifier = data.defense_modifier;
  97. speed_modifier = data.speed_modifier;
  98. dexterity_modifier = data.dexterity_modifier;
  99. //apiRequest2
  100. happy = data.happy.current;
  101. energy = data.energy.current;
  102. //apiRequest3
  103. gymNumber = data.active_gym - 1;
  104. Gym = Gymlist2[gymNumber].Gym;
  105. //apiRequest4
  106. var string;
  107. if (data.hasOwnProperty('property_perks')) {
  108. for (i = 0; i < data.property_perks.length; i++) {
  109. string = data.property_perks[i];
  110. if (string.includes('gym gains')) {
  111. n = parseFloat(data.property_perks[i].match(/\d+/)[0]);
  112. n = (n / 100) + 1;
  113. modifierAll *= n;
  114. }
  115. }
  116. }
  117. if (data.hasOwnProperty('education_perks')) {
  118. for (i = 0; i < data.education_perks.length; i++) {
  119. string = data.education_perks[i];
  120. modifierAll *= (string.includes('1% gym gains')) ? 1.01 : 1;
  121. modifierDex *= (string.includes('dexterity gym gains')) ? 1.01 : 1;
  122. modifierDef *= (string.includes('defense gym gains')) ? 1.01 : 1;
  123. modifierSpe *= (string.includes('speed gym gains')) ? 1.01 : 1;
  124. modifierStr *= (string.includes('strength gym gains')) ? 1.01 : 1;
  125. }
  126. }
  127. if (data.hasOwnProperty('company_perks')) {
  128. for (i = 0; i < data.company_perks.length; i++) {
  129. string = data.company_perks[i];
  130. modifierDex *= (string.includes('dexterity gym gains')) ? 1.1 : 1;
  131. modifierDef *= (string.includes('defense gym gains')) ? 1.1 : 1;
  132. modifierAll *= (string.includes('gym gains')) ? 1.03 : 1;
  133. }
  134. }
  135. if (data.hasOwnProperty('book_perks')) {
  136. for (i = 0; i < data.book_perks.length; i++) {
  137. string = data.book_perks[i];
  138. modifierAll *= (string.includes('all gym gains')) ? 1.2 : 1;
  139. modifierStr *= (string.includes('strength gym gains')) ? 1.3 : 1;
  140. modifierDef *= (string.includes('defense gym gains')) ? 1.3 : 1;
  141. modifierSpe *= (string.includes('speed gym gains')) ? 1.3 : 1;
  142. modifierDex *= (string.includes('dexterity gym gains')) ? 1.3 : 1;
  143. }
  144. }
  145. if (data.hasOwnProperty('faction_perks')) {
  146. for (i = 0; i < data.faction_perks.length; i++) {
  147. string = data.faction_perks[i];
  148. if (string.includes('gym gains')) {
  149. n = parseFloat(string.match(/\d+/)[0]);
  150. n = (n / 100) + 1;
  151. if (string.includes('strength')) {
  152. modifierStr *= n;
  153. }
  154. else if (string.includes('speed')) {
  155. modifierSpe *= n;
  156. }
  157. else if (string.includes('defense')) {
  158. modifierDef *= n;
  159. }
  160. else if (string.includes('dexterity')) {
  161. modifierDex *= n;
  162. }
  163. }
  164. }
  165. }
  166. console.log(modifierStr, modifierSpe, modifierDef, modifierDex);
  167. modifierStr *= modifierAll;
  168. modifierSpe *= modifierAll;
  169. modifierDef *= modifierAll;
  170. modifierDex *= modifierAll;
  171. var GymDotsSpe = Gymlist2[gymNumber].Spe;
  172. var GymDotsDef = Gymlist2[gymNumber].Def;
  173. var GymDotsDex = Gymlist2[gymNumber].Dex;
  174. var GymDotsStr = Gymlist2[gymNumber].Str;
  175. var EnergyPerTrain = Gymlist2[gymNumber].Energy;
  176. var trains = parseInt(energy / EnergyPerTrain);
  177. //new formula
  178. var gainSpe = calculateTotal(speed, happy, GymDotsSpe, EnergyPerTrain, modifierSpe, 'spe', trains);
  179. var gainDef = calculateTotal(defense, happy, GymDotsDef, EnergyPerTrain, modifierDef, 'def', trains);
  180. var gainDex = calculateTotal(dexterity, happy, GymDotsDex, EnergyPerTrain, modifierDex, 'dex', trains);
  181. var gainStr = calculateTotal(strength, happy, GymDotsStr, EnergyPerTrain, modifierStr, 'str', trains);
  182.  
  183. var [strText, defText, speText, dexText] = [gainStr,gainDef,gainSpe,gainDex].map(gain=>{
  184. return `<br><span style="float: left;margin:5px;background:#494949;border: 4px solid #494949">+${ROUND(gain[0],2)}</span>
  185. <span style="float: right;margin:5px;background:#494949;border: 4px solid #494949"><b>+${ROUND(gain[1],2)}</b></span>`;
  186. });
  187.  
  188. var arr = [{
  189. 'speText': speText,
  190. 'value': GymDotsSpe
  191. }, {
  192. 'defText': defText,
  193. 'value': GymDotsDef
  194. }, {
  195. 'dexText': dexText,
  196. 'value': GymDotsDex
  197. }, {
  198. 'strText': strText,
  199. 'value': GymDotsStr
  200. }];
  201. var largest = [[{
  202. 'value': 0
  203. },]];
  204. arr.forEach(function(element,i) {
  205. if (element.value > largest[0][0].value) {
  206. largest = [[element,i]];
  207. }
  208. else if (element.value == largest[0][0].value) {
  209. largest.push([element,i]);
  210. }
  211. });
  212. largest.forEach(function(e) {
  213. let i=e[1];
  214. e=e[0];
  215. var x = Object.keys(e)[0];
  216. arr[i][x] = e[x].replaceAll('solid #494949', 'inset lightgreen');
  217. });
  218. $('#gymroot h3:contains("Strength")').parent().append(arr[3].strText);
  219. $('#gymroot h3:contains("Defense")').parent().append(arr[1].defText);
  220. $('#gymroot h3:contains("Speed")').parent().append(arr[0].speText);
  221. $('#gymroot h3:contains("Dexterity")').parent().append(arr[2].dexText);
  222.  
  223. // old selection method - stopped working
  224. //$(arr[3].strText).insertAfter('#strength-val');
  225. //$(arr[1].defText).insertAfter('#defense-val');
  226. //$(arr[0].speText).insertAfter('#speed-val');
  227. //$(arr[2].dexText).insertAfter('#dexterity-val');
  228. });
  229. }).catch((error) => {
  230. console.error('Error:', error);
  231. //still needs error handeling
  232. });
  233. }
  234. }
  235.  
  236. function manualEstimator(){
  237. let tempID = ($('#gymroot').length) ? '#gymroot' : '#mainContainer';
  238. $(tempID).prepend(`
  239. <div id="customEstimate" class="tutorial-cont m-top10">
  240. <div class="title-gray top-round" role="heading" aria-level="5">
  241. <span>Custom Estimation</span>
  242. </div>
  243. <div class="tutorial-desc bottom-round cont-gray p10" tabindex="0">
  244. <p>Happy: <input id="happy" type="number" class="input___2D0YE" required> Energy: <input type="number" id="energy" class="input___2D0YE" required></p>
  245. <p>Gym: <select id="gyms">
  246. <option>Premier Fitness</option><option>Average Joes</option><option>Woody's Workout</option><option>Beach Bods</option><option>Silver Gym</option><option>Pour Femme</option><option>Davies Den</option><option>Global Gym</option><option>Knuckle Heads</option><option>Pioneer Fitness</option><option>Anabolic Anomalies</option><option>Core</option><option>Racing Fitness</option><option>Complete Cardio</option><option>Legs Bums and Tums</option><option>Deep Burn</option><option>Apollo Gym</option><option>Gun Shop</option><option>Force Training</option><option>Cha Cha's</option><option>Atlas</option><option>Last Round</option><option>The Edge</option><option>George's</option><option>Balboas Gym</option><option>Frontline Fitness</option><option>Gym </option><option>Mr Isoyamas</option><option>Total Rebound</option><option>Elites</option><option>Sports Science Lab</option>
  247. </select></p>
  248. <p>speed: <input id="spe" type="number" class="input___2D0YE" required> str: <input id="str" type="number" class="input___2D0YE" required> dex: <input id="dex" type="number" class="input___2D0YE" required> def: <input id="def" type="number" class="input___2D0YE" required>
  249. <p><button id="estimateButton">calculate</button>
  250. </div>
  251. </div>`);
  252. $('#customEstimate').hide();
  253. $('#skip-to-content').css({
  254. color: 'green',
  255. cursor: 'pointer'
  256. });
  257. $('#skip-to-content').on('click', function() {
  258. $('#customEstimate').toggle("slide", {
  259. direction: "right"
  260. }, 500);
  261. });
  262. $('#estimateButton').on('click', function() {
  263. let energy = $('#energy').val();
  264. let happy = $('#happy').val();
  265. let gym = $('#gyms option:selected').text();
  266. let gymThis = Gymlist2.filter(function(g) {
  267. return g.Gym == gym
  268. });
  269. let modifierStr = 1;
  270. let modifierSpe = 1;
  271. let modifierDef = 1;
  272. let modifierDex = 1;
  273. speed = parseInt($('#spe').val());
  274. defense = parseInt($('#def').val());
  275. dexterity = parseInt($('#dex').val());
  276. strength = parseInt($('#str').val());
  277. let GymDotsSpe = gymThis[0].Spe;
  278. let GymDotsDef = gymThis[0].Def;
  279. let GymDotsDex = gymThis[0].Dex;
  280. let GymDotsStr = gymThis[0].Str;
  281. var EnergyPerTrain = gymThis[0].Energy;
  282. let trains = parseInt(energy / EnergyPerTrain);
  283. let gainSpe = calculateTotal(speed,happy,GymDotsSpe,EnergyPerTrain,modifierSpe,'spe',trains);
  284. let gainDef = calculateTotal(defense,happy,GymDotsDef,EnergyPerTrain,modifierDef,'def',trains);
  285. let gainDex = calculateTotal(dexterity,happy,GymDotsDex,EnergyPerTrain,modifierDex,'dex',trains);
  286. let gainStr = calculateTotal(strength,happy,GymDotsStr,EnergyPerTrain,modifierStr,'str',trains);
  287. console.table({
  288. Str: gainStr[1],
  289. Dex: gainDex[1],
  290. Def: gainDef[1],
  291. Spe: gainSpe[1]
  292. });
  293. alert(`\n
  294. speed: ${gainSpe[0]} Total:${gainSpe[1]}\n
  295. defense: ${gainDef[0]} Total:${gainDef[1]}\n
  296. dexterity: ${gainDex[0]} Total:${gainDex[1]}\n
  297. strength: ${gainStr[0]} Total:${gainStr[1]}`
  298. );
  299. });
  300. }
  301.  
  302. })();
  303.  
  304. function calculateTotal(stat,happy,dots,energyP,perks,typ,trains){
  305. let S = stat;
  306. if (S > 5e7) S = 5e7 + (S - 5e7) / (8.77635 * Math.log(S));
  307. let H = happy;
  308. let [A,B,C] = {str:[1600,1700,700],spe:[1600,2000,1350],dex:[1800,1500,1000],def:[2100,-600,1500]}[typ];
  309. console.log(perks);
  310. let result = (S * ROUND(1 + 0.07 * ROUND(Math.log(1+H/250),4),4) + 8 * H**1.05 + (1-(H/99999)**2) * A + B) * (1/200000) * dots * energyP * perks;
  311. console.log(result)
  312. let total = 0;
  313. for(let i=0;i<trains;i++){
  314. S = stat+total;
  315. if (S > 5e7) S = 5e7 + (S - 5e7) / (8.77635 * Math.log(S));
  316. total += (S * ROUND(1 + 0.07 * ROUND(Math.log(1+H/250),4),4) + 8 * H**1.05 + (1-(H/99999)**2) * A + B) * (1/200000) * dots * energyP * perks;
  317. let dH = ROUND(energyP/2, 0);
  318. H-=dH;
  319. }
  320. return [result,total];
  321. }
  322.  
  323. function ROUND(num,places) {
  324. return +(Math.round(num + "e+" + places) + "e-" + places);
  325. }
  326.  
  327. function handleErrorCode(errorObj){
  328.  
  329. switch(errorObj.code){
  330. case 2:
  331. //Incorrect Key
  332. poppupMesage("Did you reset your apiKey? Please insert your API key in order to use gymtorngains:", "apikey");
  333.  
  334. break;
  335. case 5:
  336. //Too many requests
  337. var time = new Date();
  338. time.setMinutes(time.getMinutes() + 5);
  339. document.cookie = "GTGdisabled=true; expires=" + time;
  340. poppupMesage("Too many request, wait 5 minutes: until " +time, "warning");
  341.  
  342. break;
  343. case 14:
  344. //Daily read limit reached
  345. var tomorrow = new Date();
  346. tomorrow.setDate(new Date().getDate()+1);
  347. tomorrow.setHours(0,0,0,0);
  348. document.cookie = "GTGdisabled=true; expires=" + tomorrow;
  349. poppupMesage("Hit daily api limit, wait until tomorrow: until "+tomorrow, "warning");
  350.  
  351. break;
  352. default:
  353. console.error(errorObj.error);
  354. }
  355.  
  356. }
  357.  
  358. function poppupMesage(message, poppupType){
  359. // poppup message to inform you on setting api key
  360. var span = document.createElement('span');
  361. span.onclick = function () {
  362. this.parentElement.parentElement.removeChild(this.parentElement);
  363. };
  364. span.innerHTML = '&times;';
  365. span.style = "margin-left: 25px;color:white;font-weight:bold;\nfloat: right;font-size:30px;line-height:20px;cursor:pointer;";
  366.  
  367. var child = document.createElement('div');
  368. child.style = "z-index:999999;width:100%;height:auto;position:fixed;top:0px;\ntext-align:center;background-color:#5D3A9B;color:rgb(185,166,45);padding-bottom:1%;padding-top:1%;";
  369. child.innerHTML = message + '\n';
  370. var input = document.createElement('input');
  371. var button = document.createElement('button');
  372. button.style = 'background-color:black; color:white;';
  373. button.innerHTML = "submit";
  374. if (poppupType== "apikey"){
  375. child.append(input);
  376. child.append(button);
  377. }
  378. child.appendChild(span);
  379. document.body.appendChild(child);
  380.  
  381. button.onclick = function(e) {
  382. window.localStorage.enXrayApiKey = en_de_code(input.value,playerId,0);
  383. window.location.href = window.location.href;
  384. }
  385.  
  386. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址