Eternity Tower Stats

Adds various stats to the Eternity Tower game

  1. // ==UserScript==
  2. // @name Eternity Tower Stats
  3. // @icon https://www.eternitytower.net/favicon.png
  4. // @namespace http://mean.cloud/
  5. // @version 1.32
  6. // @description Adds various stats to the Eternity Tower game
  7. // @match *://eternitytower.net/*
  8. // @match *://www.eternitytower.net/*
  9. // @match http://localhost:3000/*
  10. // @author psouza4@gmail.com
  11. // @copyright 2017-2023, MeanCloud
  12. // @run-at document-end
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // ==/UserScript==
  16.  
  17.  
  18. ////////////////////////////////////////////////////////////////
  19. ////////////// ** SCRIPT GLOBAL INITIALIZATION ** //////////////
  20. function startup() { ET_StatsUIMod(); }
  21. ET_Stat_UserID = "";
  22. ET_Stat_CombatID = "";
  23. ET_Stat_CritChance = 0;
  24. ET_Stat_CritDamage = 0;
  25. ET_Stat_HealingPower = 0;
  26. ET_Stat_DamageTaken = 0;
  27. ET_Stat_MP = 0;
  28. ET_JustExpanded = false;
  29. ET_LastModal = null;
  30. ET_LastForm = null;
  31. ////////////////////////////////////////////////////////////////
  32.  
  33.  
  34. ET_StatsUIMod = function()
  35. {
  36. ET.MCMF.Ready(function()
  37. {
  38. //ET.MCMF.WantDebug = true;
  39.  
  40. Meteor.connection._stream.on('message', function(sMeteorRawData)
  41. {
  42. try
  43. {
  44. var oMeteorData = JSON.parse(sMeteorRawData);
  45.  
  46. if (oMeteorData.collection == "users")
  47. {
  48. //console.log(oMeteorData);
  49.  
  50. ET_Stat_UserID = oMeteorData.id;
  51. }
  52.  
  53. if (oMeteorData.collection == "combat")
  54. if ((oMeteorData.fields.owner === ET_Stat_UserID) &&( ET_Stat_CombatID === ""))
  55. ET_Stat_CombatID = oMeteorData.id;
  56.  
  57. if (oMeteorData.collection == "combat")
  58. {
  59. if ((oMeteorData.fields.owner === ET_Stat_UserID) || (oMeteorData.id === ET_Stat_CombatID))
  60. {
  61. //console.log(oMeteorData);
  62.  
  63. ET_Stat_CritChance = oMeteorData.fields.stats.criticalChance;
  64. ET_Stat_CritDamage = oMeteorData.fields.stats.criticalDamage;
  65. ET_Stat_HealingPower = oMeteorData.fields.stats.healingPower;
  66. ET_Stat_DamageTaken = oMeteorData.fields.stats.damageTaken;
  67. ET_Stat_MP = oMeteorData.fields.stats.magicPower;
  68.  
  69. /*
  70. var oHPEl = jQ("div.bg-danger").parent().parent().find("div.d-flex > i.extra-small-icon").parent();
  71.  
  72. if (jQ("#PET_DemonMaxHP").length === 0)
  73. oHPEl.append("<span id=\"PET_DemonMaxHP\" style=\"white-space: nowrap; font-size: 9pt;\"></span>");
  74.  
  75. jQ("#PET_DemonMaxHP").html("&nbsp;&nbsp;(demon &lt; " + ((oMeteorData.fields.stats.healthMax * 0.2) + 1).toFixed(0) + ")");
  76. */
  77. }
  78. }
  79. }
  80. catch (err) { }
  81. });
  82. });
  83.  
  84. ET.MCMF.Loaded(function()
  85. {
  86. ET.MCMF.StatsUIMod = { };
  87.  
  88. ET.MCMF.StatsUIMod.WantAdventureLoot = (GM_getValue("PETStatusUI_WantAdventureLoot") !== false); // default true
  89. //GM_setValue("PETSearch_Color", jQ("#PETSItemColor") .is(":checked"));
  90.  
  91. // Set background tasks
  92. ET_StatsUIMod_DPSShow();
  93. });
  94. };
  95.  
  96. ET_StatsUIMod_GetAdventure = function(sMatchID)
  97. {
  98. // oAdventure
  99. // .duration
  100. // .endDate
  101. // .floor
  102. // .icon
  103. // .id
  104. // .length
  105. // .level
  106. // .name
  107. // .room
  108. // .type
  109. // .startDate
  110. var oAdventureData;
  111.  
  112. [...Package.meteor.global.Accounts.connection._stores.adventures._getCollection()._collection._docs._map.values()][0].adventures.forEach(function(oAdventure)
  113. {
  114. try
  115. {
  116. if (oAdventure.id === sMatchID)
  117. oAdventureData = oAdventure;
  118. }
  119. catch (err) { }
  120. });
  121.  
  122. return oAdventureData;
  123. };
  124.  
  125. var sETStatsDB = "";
  126. var ETStatsDB_PQ = [];
  127. var ETStatsDB_Tower = [];
  128.  
  129. ET_StatsUIMod_ConvertItemIDToImage = function(sItemID)
  130. {
  131. var s = sItemID;
  132.  
  133. var sExt = ".svg";
  134.  
  135. if (endsWith(s, "_essence")) sExt = ".png";
  136. if (endsWith(s, "_shield")) sExt = ".png";
  137. if (endsWith(s, "_scimitar")) sExt = ".png";
  138. if (endsWith(s, "_broad_sword")) sExt = ".png";
  139. if (endsWith(s, "_plate") && (s !== "opal_chest_plate")) sExt = ".png";
  140. if (s.indexOf("_wizard") !== -1) sExt = ".png";
  141. if (endsWith(s, "_battle_axe")) sExt = ".png";
  142. if (endsWith(s, "_long_sword")) sExt = ".png";
  143. if (endsWith(s, "_helm")) sExt = ".png";
  144. if (endsWith(s, "_knife")) sExt = ".png";
  145. if (endsWith(s, "_wand")) sExt = ".png";
  146. if (endsWith(s, "_spear")) sExt = ".png";
  147. if (endsWith(s, "_rapiers")) sExt = ".png";
  148. if (endsWith(s, "_dagger")) sExt = ".png";
  149. if (endsWith(s, "_log")) sExt = ".png";
  150. if (startsWith(s, "ore_")) { s = s.substr(4); sExt = ".png"; }
  151. if (startsWith(s, "poison_shard")) sExt = ".png";
  152. if (startsWith(s, "fire_shard")) sExt = ".png";
  153. if (startsWith(s, "earth_shard")) sExt = ".png";
  154. if (startsWith(s, "air_shard")) sExt = ".png";
  155. if (startsWith(s, "water_shard")) sExt = ".png";
  156.  
  157. if (s.indexOf("_tome") !== -1) s = "tome";
  158.  
  159. while (s.indexOf("broad_sword") !== -1) s = s.replace("broad_sword", "broadsword");
  160.  
  161. while (s.indexOf("_a") !== -1) s = s.replace("_a", "A");
  162. while (s.indexOf("_b") !== -1) s = s.replace("_b", "B");
  163. while (s.indexOf("_c") !== -1) s = s.replace("_c", "C");
  164. while (s.indexOf("_d") !== -1) s = s.replace("_d", "D");
  165. while (s.indexOf("_e") !== -1) s = s.replace("_e", "E");
  166. while (s.indexOf("_f") !== -1) s = s.replace("_f", "F");
  167. while (s.indexOf("_g") !== -1) s = s.replace("_g", "G");
  168. while (s.indexOf("_h") !== -1) s = s.replace("_h", "H");
  169. while (s.indexOf("_i") !== -1) s = s.replace("_i", "I");
  170. while (s.indexOf("_j") !== -1) s = s.replace("_j", "J");
  171. while (s.indexOf("_k") !== -1) s = s.replace("_k", "K");
  172. while (s.indexOf("_l") !== -1) s = s.replace("_l", "L");
  173. while (s.indexOf("_m") !== -1) s = s.replace("_m", "M");
  174. while (s.indexOf("_n") !== -1) s = s.replace("_n", "N");
  175. while (s.indexOf("_o") !== -1) s = s.replace("_o", "O");
  176. while (s.indexOf("_p") !== -1) s = s.replace("_p", "P");
  177. while (s.indexOf("_q") !== -1) s = s.replace("_q", "Q");
  178. while (s.indexOf("_r") !== -1) s = s.replace("_r", "R");
  179. while (s.indexOf("_s") !== -1) s = s.replace("_s", "S");
  180. while (s.indexOf("_t") !== -1) s = s.replace("_t", "T");
  181. while (s.indexOf("_u") !== -1) s = s.replace("_u", "U");
  182. while (s.indexOf("_v") !== -1) s = s.replace("_v", "V");
  183. while (s.indexOf("_w") !== -1) s = s.replace("_w", "W");
  184. while (s.indexOf("_x") !== -1) s = s.replace("_x", "X");
  185. while (s.indexOf("_y") !== -1) s = s.replace("_y", "Y");
  186. while (s.indexOf("_z") !== -1) s = s.replace("_z", "Z");
  187. s = s.split('_').join('');
  188.  
  189. s = s + sExt;
  190.  
  191. return s;
  192. };
  193.  
  194. ET_StatsUIMod_GetDropsForTower = function(iFloor, iRoom)
  195. {
  196. var sResults = "";
  197.  
  198. try
  199. {
  200. if (ETStatsDB_Tower[iFloor][iRoom] !== undefined)
  201. {
  202. jQuery.makeArray(ETStatsDB_Tower[iFloor][iRoom]).forEach(function(dropInfo)
  203. {
  204. try
  205. {
  206. //if (sResults !== "") sResults += ", ";
  207. //sResults += dropInfo.name + " (" + dropInfo.percent.toString() + "%)";
  208.  
  209. var s = ET_StatsUIMod_ConvertItemIDToImage(dropInfo.name);
  210.  
  211. var sHover = dropInfo.name + " (" + dropInfo.percent.toString() + "%)";
  212. //sResults += "<img src=\"/icons/" + s + "\" class=\"ml-1 extra-small-icon\" />";
  213. sResults += "<img src=\"/icons/" + s + "\" style=\"width: 24px; height: 24px; font-size: 24px; line-height: 24px;\" alt=\"" + sHover + "\" title=\"" + sHover + "\">";
  214. }
  215. catch (err) { }
  216. });
  217. }
  218. }
  219. catch (err) { }
  220.  
  221. return sResults;
  222. };
  223.  
  224. ET_StatsUIMod_LoadETStatsDatabase = function()
  225. {
  226. if (sETStatsDB !== "")
  227. return;
  228.  
  229. try
  230. {
  231. sETStatsDB = "busy";
  232.  
  233. jQ.get("https://www.damned.cloud/ETStats/", function(data)
  234. {
  235. try
  236. {
  237. // don't hold bad data
  238. if (data.indexOf("Level 50-54") === -1)
  239. {
  240. sETStatsDB = "";
  241. return;
  242. }
  243.  
  244. sETStatsDB = data;
  245. ETStatsDB_PQ = [];
  246. ETStatsDB_Tower = [];
  247.  
  248. //console.log("ET Stats loaded!");
  249. //console.log(sETStatsDB);
  250.  
  251. let rawPQData = ChopperBlank(sETStatsDB, "<pre>", "Tower").trim().split("Level ");
  252.  
  253. //ETStatsDB_Tower
  254. jQuery.makeArray(rawPQData).forEach(function(rawPQChunk)
  255. {
  256. //console.log("Raw PQ chunk: " + rawPQChunk.trim());
  257.  
  258. let iRangeStart = 0;
  259. let iRangeEnd = 0;
  260.  
  261. jQuery.makeArray(rawPQChunk.trim().split("\n")).forEach(function(rawPQLine, idx, arr)
  262. {
  263. try
  264. {
  265. rawPQLine = rawPQLine.trim();
  266.  
  267. //console.log(idx.toString() + " :: " + rawPQLine);
  268.  
  269. if (idx === 0)
  270. {
  271. iRangeStart = CInt(ChopperBlank(rawPQLine, "", "-"));
  272. iRangeEnd = CInt(ChopperBlank(rawPQLine, "-", " "));
  273. }
  274. else if ((iRangeStart > 0) && (iRangeEnd > 0))
  275. {
  276. let temp_Percent = CDbl(ChopperBlank(rawPQLine, "", "%"));
  277. let temp_Name = ChopperBlank(rawPQLine, " - ", " (").trim();
  278.  
  279. let oDataObj = { name: temp_Name, percent: temp_Percent };
  280.  
  281. for (let i = iRangeStart; i <= iRangeEnd; i++)
  282. {
  283. if (ETStatsDB_PQ[i] === undefined)
  284. ETStatsDB_PQ[i] = [];
  285.  
  286. ETStatsDB_PQ[i].push(oDataObj);
  287. }
  288.  
  289. //console.log("PQ data recorded: L" + iRangeStart.toString() + "-L" + iRangeEnd.toString() + " " + JSON.stringify(oDataObj));
  290. }
  291. }
  292. catch (err)
  293. {
  294. console.log("PQ line parse failure: " + JSON.stringify(err));
  295. }
  296. });
  297. });
  298.  
  299. let rawTowerData = ChopperBlank(sETStatsDB, "Tower F0R0", "</pre>").trim().split("Tower ");
  300.  
  301. //ETStatsDB_Tower
  302. jQuery.makeArray(rawTowerData).forEach(function(rawTowerChunk)
  303. {
  304. let iFloor = CInt(ChopperBlank(rawTowerChunk, "F", "R"));
  305. let iRoom = CInt(ChopperBlank(rawTowerChunk, "R", " - "));
  306.  
  307. // don't hold data for full tower floor runs or any invalid data
  308. if ((iFloor === 0) || (iRoom === 0))
  309. return;
  310.  
  311. jQuery.makeArray(rawTowerChunk.trim().split("\n")).forEach(function(rawTowerLine, idx, arr)
  312. {
  313. try
  314. {
  315. rawTowerLine = rawTowerLine.trim();
  316.  
  317. //console.log(idx.toString() + " :: " + rawTowerLine);
  318.  
  319. if (idx === 0)
  320. return;
  321.  
  322. let temp_Percent = CDbl(ChopperBlank(rawTowerLine, "", "%"));
  323. let temp_Name = ChopperBlank(rawTowerLine, " - ", " (").trim();
  324.  
  325. let oDataObj = { name: temp_Name, percent: temp_Percent };
  326.  
  327. if (ETStatsDB_Tower[iFloor] === undefined)
  328. ETStatsDB_Tower[iFloor] = [];
  329. if (ETStatsDB_Tower[iFloor][iRoom] === undefined)
  330. ETStatsDB_Tower[iFloor][iRoom] = [];
  331.  
  332. if (iFloor == 1) {
  333. if (temp_Name == "ore_tungsten") {
  334. return;
  335. }
  336. }
  337.  
  338. ETStatsDB_Tower[iFloor][iRoom].push(oDataObj);
  339.  
  340. //console.log("Tower data recorded: F" + iFloor.toString() + "R" + iRoom.toString() + " " + JSON.stringify(oDataObj));
  341. }
  342. catch (err)
  343. {
  344. console.log("Tower line parse failure: " + JSON.stringify(err));
  345. }
  346. });
  347. });
  348.  
  349. let i;
  350.  
  351. for (i = 0; i <= 1000; i++)
  352. {
  353. if (ETStatsDB_PQ[i] !== undefined)
  354. {
  355. //console.log("PQ L" + i.toString() + " sorted!");
  356.  
  357. ETStatsDB_PQ[i].sort(function(dropInfo_a, dropInfo_b)
  358. {
  359. if (dropInfo_a.percent > dropInfo_b.percent) return -1;
  360. if (dropInfo_a.percent < dropInfo_b.percent) return 1;
  361. return 0;
  362. });
  363. }
  364. }
  365.  
  366. for (i = 0; i <= 30; i++)
  367. {
  368. if (ETStatsDB_Tower[i] !== undefined)
  369. {
  370. for (let j = 0; j <= 30; j++)
  371. {
  372. if (ETStatsDB_Tower[i][j] !== undefined)
  373. {
  374. //console.log("Tower F" + i.toString() + "R" + j.toString() + " sorted!");
  375.  
  376. ETStatsDB_Tower[i][j].sort(function(dropInfo_a, dropInfo_b)
  377. {
  378. if (dropInfo_a.percent > dropInfo_b.percent) return -1;
  379. if (dropInfo_a.percent < dropInfo_b.percent) return 1;
  380. return 0;
  381. });
  382. }
  383. }
  384. }
  385. }
  386. }
  387. catch (err) { sETStatsDB = ""; }
  388. });
  389. }
  390. catch (err) { }
  391. };
  392.  
  393. ET_StatsUIMod_DPSShow = function()
  394. {
  395. var i = 0;
  396. var oStatLines = null;
  397. var sBareDamageRange = "";
  398. var sBareAttackSpeed = "";
  399. var sBareCriticalChance = "";
  400. var dDamageMin = 0.0;
  401. var dDamageMax = 0.0;
  402. var sDamagePartMin = "";
  403. var sDamagePartMax = "";
  404. var dAverageDamageAvgQuality = 0.0;
  405. var dAverageDamageMaxQuality = 0.0;
  406. var sThisLine = "";
  407. var sThisLineText = "";
  408. var dAttackSpeed = 0.0;
  409. var dActualDPSAverageQuality = 0.0;
  410. var dActualDPSMaxQuality = 0.0;
  411. var dCriticalChance = 0.0;
  412.  
  413. ///////////////////////////////////////////////////////////////////////////////////////
  414. //
  415. // Adventure Details
  416. //
  417. ET_StatsUIMod_LoadETStatsDatabase(); // loads on demand
  418.  
  419. try
  420. {
  421. // Options
  422. if ((ET.MCMF.GetActiveTab() === "combat") /* && (ET.MCMF.GetActiveTabSection() === "adventures") */)
  423. {
  424. if (jQ("div.PETStatusUI_Menu").length === 0)
  425. {
  426. var oTemp = jQ(jQ("body div.body-content div div div div[style=\"margin-bottom: 5px;\"]").get(0));
  427. if (oTemp.text().trim() == "Buy adventure"); // sanity check
  428. {
  429. oTemp = oTemp.parent();
  430.  
  431. oTemp.before("<div class=\"PETStatusUI_Menu d-flex flex-row flex-wrap\"></div>");
  432. oTemp.appendTo("div.PETStatusUI_Menu");
  433.  
  434. oTemp = jQ("div.PETStatusUI_Menu");
  435.  
  436. oTemp.prepend
  437. (
  438. "<div>" +
  439. "<div style=\"margin-bottom: 5px;\">Options</div>" +
  440. "<button class=\"buy-new-adventure btn btn-secondary PETStatusUI_btnShowHideLoot\">Loot: " + ((ET.MCMF.StatsUIMod.WantAdventureLoot) ? "Shown" : "Hidden") + "</button>" +
  441. "</div>"
  442. );
  443.  
  444. oTemp.children("div").addClass("d-flex flex-column my-1 mx-1");
  445. oTemp.find("button").css("height", "40px").css("max-height", "40px").css("line-height", "24px"); // normalize the button heights
  446.  
  447. jQ(".PETStatusUI_btnShowHideLoot").click(function()
  448. {
  449. ET.MCMF.StatsUIMod.WantAdventureLoot = !ET.MCMF.StatsUIMod.WantAdventureLoot;
  450. GM_setValue("PETStatusUI_WantAdventureLoot", ET.MCMF.StatsUIMod.WantAdventureLoot);
  451. jQ(".PETStatusUI_btnShowHideLoot").text((ET.MCMF.StatsUIMod.WantAdventureLoot) ? "Loot: Shown" : "Loot: Hidden");
  452. });
  453. }
  454. }
  455.  
  456. // Adventure loot lines
  457. if (ET.MCMF.StatsUIMod.WantAdventureLoot)
  458. {
  459. jQ("div.PETSDetails_error").remove();
  460.  
  461. jQ("div.adventure-item-container").each(function()
  462. {
  463. try
  464. {
  465. var sAdvID = jQ(this).find("button").attr("data-id");
  466.  
  467. var oAdventureData = ET_StatsUIMod_GetAdventure(sAdvID);
  468.  
  469. if (jQ(this).find("div.PETSDetails_success").length > 0)
  470. return;
  471.  
  472. jQ(this).find("div.PETSDetails").remove();
  473.  
  474. var sLoot = ET_StatsUIMod_GetDropsForTower(oAdventureData.floor, oAdventureData.room);
  475.  
  476. if (sLoot !== "")
  477. {
  478. jQ(this).append("<div class=\"d-flex PETSDetails PETSDetails_success\"><div class=\"d-flex\" style=\"margin-left: 60px;\">" + sLoot + "</div></div>\r\n");
  479. }
  480. else
  481. {
  482. jQ(jQ(this).find("div.ml-3").get(0)).append("<div class=\"PETSDetails PETSDetails_error\">(no loot from F" + oAdventureData.floor.toString() + "R" + oAdventureData.room.toString() + ")</div>\r\n");
  483. //jQ(jQ(this).find("div.mx-3").get(0)).append("<div class=\"PETSDetails PETSDetails_error\"><a target=\"_blank\" href=\"http://etstats.com/debug.html\">ETStats Loot List</a></div>\r\n");
  484. }
  485. }
  486. catch (err) { }
  487. });
  488. }
  489. else
  490. jQ(".PETSDetails").remove();
  491. }
  492. else
  493. {
  494. jQ("div.PETStatusUI_Menu").remove();
  495. }
  496. }
  497. catch (err) { ET.MCMF.Log(err); }
  498.  
  499.  
  500. //
  501. ///////////////////////////////////////////////////////////////////////////////////////
  502.  
  503.  
  504. ///////////////////////////////////////////////////////////////////////////////////////
  505. //
  506. // Stat Descriptions
  507. //
  508. jQ(".PeteUI_TooltipStat").remove();
  509. // Removed: this is baked into the actual game now
  510. /*
  511. jQ("div.item-tooltip-content div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;attacks per second</span>");
  512. jQ("div.item-tooltip-content div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;accuracy</span>");
  513. jQ("div.item-tooltip-content div i.lilIcon-criticalChance").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;crit. chance</span>");
  514. jQ("div.item-tooltip-content div i.lilIcon-healthMax").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;max. health</span>");
  515. jQ("div.item-tooltip-content div i.lilIcon-defense").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;dodge (defense)</span>");
  516. jQ("div.item-tooltip-content div i.lilIcon-armor").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;physical armor</span>");
  517. jQ("div.item-tooltip-content div i.lilIcon-magicPower").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;magic power</span>");
  518. jQ("div.item-tooltip-content div i.lilIcon-magicArmor").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;magic armor</span>");
  519. jQ("div.item-tooltip-content div i.lilIcon-healingPower").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;increased healing %</span>");
  520. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;attacks per second</span>");
  521. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;accuracy</span>");
  522. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-criticalChance").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;crit. chance</span>");
  523. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-healthMax").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;max. health</span>");
  524. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-defense").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;dodge (defense)</span>");
  525. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-armor").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;physical armor</span>");
  526. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-magicPower").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;magic power</span>");
  527. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-magicArmor").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;magic armor</span>");
  528. jQ("form.craft-amount-form div.modal-body > div i.lilIcon-healingPower").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;increased healing %</span>");
  529. */
  530. //
  531. ///////////////////////////////////////////////////////////////////////////////////////
  532.  
  533.  
  534. ///////////////////////////////////////////////////////////////////////////////////////
  535. //
  536. // Woodcutters
  537. //
  538. jQ("div.item-tooltip-content").each(function()
  539. {
  540. try
  541. {
  542. if (jQ(this).find("div.PeteUI_TooltipStatWC").length === 0)
  543. {
  544. if (jQ(this).html().toLowerCase().indexOf("lumber jack") !== -1)
  545. {
  546. jQ(this).find("div i.lilIcon-attack").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;wood cut tier</span>");
  547. jQ(this).find("div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;attacks per second</span>");
  548. jQ(this).find("div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\">&nbsp;accuracy</span>");
  549. }
  550. }
  551. }
  552. catch (err) { }
  553. });
  554. //
  555. ///////////////////////////////////////////////////////////////////////////////////////
  556.  
  557.  
  558. ///////////////////////////////////////////////////////////////////////////////////////
  559. //
  560. // Crafting Recipes
  561. //
  562. try
  563. {
  564. if (jQ("a.show-stats").length > 0)
  565. {
  566. ET_LastForm = jQ("a.show-stats").parent().parent();
  567. ET_LastModal = ET_LastForm.parent().parent().parent();
  568.  
  569. jQ("a.show-stats")[0].click(); // auto-expand base stats for crafting ranges (needed anyway to calculate extra stats)
  570. ET_JustExpanded = true;
  571. }
  572.  
  573. if ((ET_LastModal !== null) && (ET_LastModal.hasClass("show")) && (ET_JustExpanded === true))
  574. {
  575. var oForm = ET_LastForm;
  576. //oForm = jQ("form.craft-amount-form");
  577.  
  578. if (oForm.html().indexOf("Hide Stat Range") !== -1)
  579. {
  580. oStatLines = oForm.find("div.modal-body > div");
  581.  
  582. for (i = 1; i < oStatLines.length; i++)
  583. {
  584. sThisLine = jQ(oStatLines.get(i)).html().trim();
  585. sThisLineText = jQ(oStatLines.get(i)).text().trim();
  586.  
  587. if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") === -1))
  588. continue;
  589.  
  590. if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sBareDamageRange === "")) sBareDamageRange = sThisLineText + " [[#" + i.toString() + "]]";
  591. else if (sThisLine.indexOf("lilIcon-attackSpeed ") !== -1) sBareAttackSpeed = sThisLineText + " [[#" + i.toString() + "]]";
  592. else if (sThisLine.indexOf("lilIcon-criticalChance ") !== -1) sBareCriticalChance = sThisLineText + " [[#" + i.toString() + "]]";
  593. }
  594.  
  595. //console.log("******************BEGIN******************");
  596. //console.log("Bare DPS: " + sBareDamageRange);
  597. //console.log("Bare attack speed: " + sBareAttackSpeed);
  598. //console.log("Bare crit chance: " + sBareCriticalChance);
  599. //console.log("*******************END*******************");
  600.  
  601. sBareDamageRange = ChopperBlank(sBareDamageRange.replace(' attack', '').replace(' damage', '') + "\n", "", "\n").trim();
  602. sBareAttackSpeed = ChopperBlank(sBareAttackSpeed.replace(' attack speed', '') + "\n", "", "\n").trim();
  603. sBareCriticalChance = ChopperBlank(sBareCriticalChance.replace(' critical chance', '') + "\n", "", "\n").trim();
  604.  
  605. //console.log("******************BEGIN******************");
  606. //console.log("Bare DPS: " + sBareDamageRange);
  607. //console.log("Bare attack speed: " + sBareAttackSpeed);
  608. //console.log("Bare crit chance: " + sBareCriticalChance);
  609. //console.log("*******************END*******************");
  610.  
  611. if (sBareDamageRange.indexOf("(") !== -1)
  612. {
  613. sDamagePartMin = ChopperBlank(sBareDamageRange, "", ") - (") + ")";
  614. sDamagePartMax = "(" + ChopperBlank(sBareDamageRange, ") - (", "");
  615.  
  616. var dDamageRangeLow1 = CDbl(ChopperBlank(sDamagePartMin, "(", " - ").trim());
  617. var dDamageRangeLow2 = CDbl(ChopperBlank(sDamagePartMin, " - ", ")").trim());
  618. dDamageMin = (dDamageRangeLow1 + dDamageRangeLow2) / 2.0;
  619. var dDamageRangeHigh1 = CDbl(ChopperBlank(sDamagePartMax, "(", " - ").trim());
  620. var dDamageRangeHigh2 = CDbl(ChopperBlank(sDamagePartMax, " - ", ")").trim());
  621. dDamageMax = (dDamageRangeHigh1 + dDamageRangeHigh2) / 2.0;
  622.  
  623. dAverageDamageMaxQuality = ((dDamageRangeHigh2 - dDamageRangeLow2) / 2.0) + dDamageRangeLow2;
  624. }
  625. else
  626. {
  627. sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - ");
  628. sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", "");
  629.  
  630. dDamageMin = CDbl(sDamagePartMin);
  631. dDamageMax = CDbl(sDamagePartMax);
  632.  
  633. dAverageDamageMaxQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin;
  634. }
  635.  
  636. dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin;
  637.  
  638. dAttackSpeed = CDbl(sBareAttackSpeed);
  639. dCriticalChance = CDbl(sBareCriticalChance);
  640.  
  641. if (dCriticalChance > 0.0)
  642. {
  643. dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0);
  644. dAverageDamageMaxQuality += dAverageDamageMaxQuality * (dCriticalChance / 100.0);
  645. }
  646.  
  647. dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed;
  648. dActualDPSMaxQuality = dAverageDamageMaxQuality * dAttackSpeed;
  649.  
  650. if (!isNaN(dActualDPSAverageQuality))
  651. {
  652. oForm.find("div.modal-body").append
  653. (
  654. "<div class=\"d-flex flex-wrap\"></div><b>Rated Damage at 50% Quality</b>\r\n" +
  655. "<div class=\"d-flex flex-wrap\"><b class=\"lilIcon-attack extra-small-icon mx-1\"></b> " + dAverageDamageAvgQuality.toFixed(1) + " (per hit / base damage for abilities)</div>\r\n" +
  656. "<div class=\"d-flex flex-wrap\"><b class=\"lilIcon-attackSpeed extra-small-icon mx-1\"></b> " + dActualDPSAverageQuality.toFixed(1) + " (per second / DPS)</div>\r\n" +
  657. "<b>Rated Damage at 100% Quality</b>\r\n" +
  658. "<div class=\"d-flex flex-wrap\"><b class=\"lilIcon-attack extra-small-icon mx-1\"></b> " + dAverageDamageMaxQuality.toFixed(1) + " (per hit / base damage for abilities)</div>\r\n" +
  659. "<div class=\"d-flex flex-wrap\"><b class=\"lilIcon-attackSpeed extra-small-icon mx-1\"></b> " + dActualDPSMaxQuality.toFixed(1) + " (per second / DPS)</div>\r\n"
  660. );
  661. }
  662.  
  663. ET_JustExpanded = false;
  664. }
  665. }
  666. }
  667. catch (err) { console.log("ERROR: " + err); }
  668. //
  669. ///////////////////////////////////////////////////////////////////////////////////////
  670.  
  671.  
  672. ///////////////////////////////////////////////////////////////////////////////////////
  673. //
  674. // Item Hover Tooltips (Combat > Equipment & Stats, Wodcutting, viewing profiles, etc.)
  675. //
  676. try
  677. {
  678. jQ("div.item-tooltip-content").each(function()
  679. {
  680. if (jQ(this).find("div.PeteUI_TooltipExp").length !== 0)
  681. return;
  682.  
  683. sBareDamageRange = "";
  684. sBareAttackSpeed = "";
  685. sBareAccuracy = "";
  686. sBareCriticalChance = "";
  687. sBareEnergyPerHit = "";
  688. sBareEnergyRegen = "";
  689. var bIsWoodcutter = false;
  690.  
  691. oStatLines = jQ(this).find("div > div");
  692.  
  693. for (i = 0; i < oStatLines.length; i++)
  694. {
  695. sThisLine = jQ(oStatLines.get(i)).html().trim();
  696. sThisLineText = jQ(oStatLines.get(i)).text().trim();
  697.  
  698. if (sThisLine.indexOf('<div class="d-flex align-items-center">') !== -1) {
  699. continue;
  700. }
  701.  
  702. //console.log("DEBUG::" + sThisLine.replaceAll('\r', '').replaceAll('\n', '\\n'));
  703. //console.log("DEBUG::" + sThisLineText.replaceAll('\r', '').replaceAll('\n', '\\n'));
  704.  
  705. if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") !== -1) && (sBareDamageRange === "")) sBareDamageRange = sThisLineText + " [[#" + i.toString() + "]]";
  706. else if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf("wood cut tier") !== -1) && (sBareDamageRange === "")) { bIsWoodcutter = true; sBareDamageRange = ChopperBlank(sThisLineText, "", "wood cut tier").trim() + " - " + ChopperBlank(sThisLineText, "", "wood cut tier").trim() + " [[#" + i.toString() + "]]"; }
  707. else if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") === -1) && (sBareDamageRange === "")) { bIsWoodcutter = true; sBareDamageRange = sThisLineText + " - " + sThisLineText + " [[#" + i.toString() + "]]"; }
  708. else if (sThisLine.indexOf("lilIcon-attackSpeed ") !== -1) sBareAttackSpeed = sThisLineText + " [[#" + i.toString() + "]]";
  709. else if (sThisLine.indexOf("lilIcon-accuracy ") !== -1) sBareAccuracy = sThisLineText + " [[#" + i.toString() + "]]";
  710. else if (sThisLine.indexOf("lilIcon-criticalChance ") !== -1) sBareCriticalChance = sThisLineText + " [[#" + i.toString() + "]]";
  711. else if (sThisLine.indexOf("lilIcon-energyPerHit ") !== -1) sBareEnergyPerHit = sThisLineText + " [[#" + i.toString() + "]]";
  712. else if (sThisLine.indexOf("lilIcon-energyRegen ") !== -1) sBareEnergyRegen = sThisLineText + " [[#" + i.toString() + "]]";
  713. }
  714.  
  715. //console.log("******************BEGIN******************");
  716. //console.log("Bare DPS: " + sBareDamageRange);
  717. //console.log("Bare attack speed: " + sBareAttackSpeed);
  718. //console.log("Bare accuracy: " + sBareAccuracy);
  719. //console.log("Bare crit chance: " + sBareCriticalChance);
  720. //console.log("Bare energy per hit: " + sBareEnergyPerHit);
  721. //console.log("Bare energy regen: " + sBareEnergyRegen);
  722. //console.log("*******************END*******************");
  723.  
  724. sBareDamageRange = ChopperBlank(sBareDamageRange.replace(' damage', '').replace(' damage', '') + "\n", "", "\n").trim();
  725. sBareAttackSpeed = ChopperBlank(sBareAttackSpeed.replace(' attack speed', '') + "\n", "", "\n").trim();
  726. sBareAccuracy = ChopperBlank(sBareAccuracy.replace(' accuracy', '').trim() + " ", "", " ").trim();
  727. sBareCriticalChance = ChopperBlank(sBareCriticalChance.replace(' critical chance', '') + "\n", "", "\n").trim();
  728. sBareEnergyPerHit = ChopperBlank(sBareEnergyPerHit.replace(' energy per hit', '') + "\n", "", "\n").trim();
  729. sBareEnergyRegen = ChopperBlank(sBareEnergyRegen.replace(' energy regen', '') + "\n", "", "\n").trim();
  730.  
  731. //console.log("******************BEGIN******************");
  732. //console.log("Bare DPS: " + sBareDamageRange);
  733. //console.log("Bare attack speed: " + sBareAttackSpeed);
  734. //console.log("Bare accuracy: " + sBareAccuracy);
  735. //console.log("Bare crit chance: " + sBareCriticalChance);
  736. //console.log("Bare energy per hit: " + sBareEnergyPerHit);
  737. //console.log("Bare energy regen: " + sBareEnergyRegen);
  738. //console.log("*******************END*******************");
  739.  
  740. sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - ");
  741. sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", "");
  742.  
  743. dDamageMin = CDbl(sDamagePartMin);
  744. dDamageMax = CDbl(sDamagePartMax);
  745.  
  746. dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin;
  747.  
  748. dAttackSpeed = CDbl(sBareAttackSpeed);
  749. dCriticalChance = CDbl(sBareCriticalChance);
  750.  
  751. if (dCriticalChance > 0.0)
  752. dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0);
  753.  
  754. dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed;
  755.  
  756. if (!isNaN(dActualDPSAverageQuality) && !bIsWoodcutter)
  757. {
  758. if (jQ(this).find("div.PeteUI_TooltipExp").length === 0)
  759. {
  760. jQ(jQ(this).find("div").get(0)).append
  761. (
  762. "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><b>Rated Damage</b>\r\n" +
  763. "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-attack extra-small-icon mx-1\"></b> " + dAverageDamageAvgQuality.toFixed(1) + " (per hit / base damage)</div>\r\n" +
  764. "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-attackSpeed extra-small-icon mx-1\"></b> " + dActualDPSAverageQuality.toFixed(1) + " (per second / DPS)</div></div>\r\n"
  765. );
  766. }
  767. }
  768. else if (CDbl(sBareEnergyPerHit) > 0.0)
  769. {
  770. if (jQ(this).find("div.PeteUI_TooltipExp").length === 0)
  771. {
  772. dActualDPSAverageQuality = dAverageDamageAvgQuality / CDbl(sBareEnergyPerHit) * CDbl(sBareEnergyRegen);
  773.  
  774. jQ(jQ(this).find("div").get(0)).append
  775. (
  776. "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><b>Rated Efficiency</b>\r\n" +
  777. "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-mining extra-small-icon mx-1\"></b> " + dActualDPSAverageQuality.toFixed(1) + " rating</div>\r\n"
  778. );
  779. }
  780. }
  781. else if ((dAttackSpeed > 0.0) && (CDbl(sBareAccuracy) > 0.0) && (bIsWoodcutter))
  782. {
  783. if (jQ(this).find("div.PeteUI_TooltipExp").length === 0)
  784. {
  785. dActualDPSAverageQuality = CDbl(sBareAccuracy) * dAttackSpeed;
  786.  
  787. var sTier = "pine logs (only)";
  788. if (CInt(dAverageDamageAvgQuality) === 5) sTier = "beech logs (and lower)";
  789. else if (CInt(dAverageDamageAvgQuality) === 10) sTier = "ash logs (and lower)";
  790. else if (CInt(dAverageDamageAvgQuality) === 15) sTier = "oak logs (and lower)";
  791. else if (CInt(dAverageDamageAvgQuality) === 20) sTier = "maple logs (and lower)";
  792. else if (CInt(dAverageDamageAvgQuality) === 25) sTier = "walnut logs (and lower)";
  793. else if (CInt(dAverageDamageAvgQuality) === 30) sTier = "cherry logs (and lower)";
  794. else if (CInt(dAverageDamageAvgQuality) === 35) sTier = "mahogany logs (and lower)";
  795. else if (CInt(dAverageDamageAvgQuality) === 40) sTier = "elm logs (and lower)";
  796. else if (CInt(dAverageDamageAvgQuality) === 45) sTier = "black logs (and lower)";
  797. else if (CInt(dAverageDamageAvgQuality) === 50) sTier = "blue gum logs (and lower)";
  798. else if (CInt(dAverageDamageAvgQuality) === 55) sTier = "cedar logs (and lower)";
  799. else if (CInt(dAverageDamageAvgQuality) === 60) sTier = "denya logs (and lower)";
  800. else if (CInt(dAverageDamageAvgQuality) === 65) sTier = "gombe logs (and lower)";
  801. else if (CInt(dAverageDamageAvgQuality) === 70) sTier = "hickory logs (and lower)";
  802. else if (CInt(dAverageDamageAvgQuality) === 75) sTier = "larch logs (and lower)";
  803. else if (CInt(dAverageDamageAvgQuality) === 80) sTier = "poplar logs (and lower)";
  804. else if (CInt(dAverageDamageAvgQuality) === 85) sTier = "tali logs (and lower)";
  805. else if (CInt(dAverageDamageAvgQuality) === 90) sTier = "willow logs (and lower)";
  806. else if (CInt(dAverageDamageAvgQuality) === 95) sTier = "teak logs (and lower)";
  807. else if (CInt(dAverageDamageAvgQuality) === 100) sTier = "ebony logs (and lower)";
  808. else if (CInt(dAverageDamageAvgQuality) === 105) sTier = "fiery logs (and lower)";
  809. else if (CInt(dAverageDamageAvgQuality) === 110) sTier = "tamarind logs (and lower)";
  810. else if (CInt(dAverageDamageAvgQuality) === 115) sTier = "magic logs (and lower)";
  811. else if (CInt(dAverageDamageAvgQuality) === 120) sTier = "petrified logs (and lower)";
  812. else if (CInt(dAverageDamageAvgQuality) === 125) sTier = "ancient logs (and lower)";
  813.  
  814. jQ(jQ(this).find("div").get(0)).append
  815. (
  816. "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><br /><b>Rated Efficiency</b>\r\n" +
  817. "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-woodcutting extra-small-icon mx-1\"></b> " + dActualDPSAverageQuality.toFixed(1) + " rating</div>\r\n" +
  818. "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-woodcutter extra-small-icon mx-1\"></b> chops " + sTier + "</div>\r\n"
  819. );
  820. }
  821. }
  822. });
  823. }
  824. catch (err) { console.log("ERROR: " + err); }
  825. //
  826. ///////////////////////////////////////////////////////////////////////////////////////
  827.  
  828.  
  829. ///////////////////////////////////////////////////////////////////////////////////////
  830. //
  831. // Combat Stats page (personal)
  832. //
  833. try
  834. {
  835. if (ET.MCMF.GetActiveTab() == "combat")
  836. {
  837. if ((ET.MCMF.IsNewCombatTab()) && (!ET.MCMF.PlayerInCombat()) && (jQ('div.battle-unit-container').length > 0))
  838. {
  839. if (jQ("div.lobby-container").find("div.mb-1").html().toLowerCase().indexOf("combat levels") !== -1)
  840. {
  841. var oCombatData = ET.MCMF.GetPlayerCombatData();
  842.  
  843. jQ(".PeteUI_CombatStat").remove();
  844.  
  845. let dDamageMin = oCombatData.stats.attack;
  846. let dDamageMax = oCombatData.stats.attackMax;
  847.  
  848. let dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin;
  849.  
  850. let dAttackSpeed = oCombatData.stats.attackSpeed;
  851. let dCriticalChance = oCombatData.stats.criticalChance;
  852.  
  853. if (dCriticalChance > 0.0)
  854. dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); // note: not using ET_Stat_CritDamage!
  855.  
  856. let dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed;
  857.  
  858. let oZerkSkill = undefined; try { oZerkSkill = jQ.makeArray(Meteor.connection._stores.abilities._getCollection().find({owner: Meteor.connection._userId}).fetch()[0].learntAbilities).filter(function(a) { return a.abilityId === "berserk" })[0]; } catch (err) { }
  859. let oDESkill = undefined; try { oDESkill = jQ.makeArray(Meteor.connection._stores.abilities._getCollection().find({owner: Meteor.connection._userId}).fetch()[0].learntAbilities).filter(function(a) { return a.abilityId === "double_edged_sword" })[0]; } catch (err) { }
  860.  
  861. let iZerkLevel = 0;
  862. let iDELevel = 0;
  863. let dDEDamage = 0.0;
  864. let dDEDamage_zerk = 0.0;
  865. let dDEDamage_zerk_WC = 0.0;
  866. let dZerkDamageBonus = 1.0;
  867.  
  868. if (oZerkSkill !== undefined)
  869. {
  870. iZerkLevel = CInt(oZerkSkill.level);
  871. dZerkDamageBonus = 1.45 + (CDbl(oZerkSkill.level) * 0.05);
  872. }
  873.  
  874. if (oDESkill !== undefined)
  875. {
  876. iDELevel = CInt(oDESkill.level);
  877. dDEDamage = (1.25 + (CDbl(oDESkill.level) * 0.75)) * dDamageMax;
  878. dDEDamage_zerk = (1.25 + (CDbl(oDESkill.level) * 0.75)) * dDamageMax * dZerkDamageBonus;
  879. dDEDamage_zerk_WC = (1.25 + (CDbl(oDESkill.level) * 0.75)) * dDamageMax * dZerkDamageBonus * 1.5;
  880. }
  881.  
  882. let sDESkillHTML = "";
  883. let sDESkillHTML_zerk = "";
  884. let sDESkillHTML_zerk_WC = "";
  885.  
  886. if (iDELevel === 0)
  887. {
  888. /* sDESkillHTML =
  889. " <div class=\"d-flex flex-wrap\">\r\n" +
  890. " <div class=\"mb-3 mr-3\">\r\n" +
  891. " <div class=\"d-flex align-items-center\">\r\n" +
  892. " <i class=\"lilIcon-noimage small-icon\">\r\n" +
  893. " <div class=\"ml-1 mb-0\"></div>\r\n" +
  894. " <small class=\"mx-3\"></small>\r\n" +
  895. " </div>\r\n" +
  896. " </div>\r\n" +
  897. " </div>\r\n"; */
  898.  
  899. sDESkillHTML =
  900. " <div class=\"d-flex flex-wrap\">\r\n" +
  901. " <div class=\"mb-3 mr-3\">\r\n" +
  902. " <div class=\"d-flex align-items-center\">\r\n" +
  903. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  904. " <div class=\"ml-1 mb-0\">Double Edged Sword</div>\r\n" +
  905. " <small class=\"mx-3\">skill missing</small>\r\n" +
  906. " </div>\r\n" +
  907. " </div>\r\n" +
  908. " </div>\r\n";
  909. }
  910. else
  911. {
  912. sDESkillHTML =
  913. " <div class=\"d-flex flex-wrap\">\r\n" +
  914. " <div class=\"mb-3 mr-3\">\r\n" +
  915. " <div class=\"d-flex align-items-center\">\r\n" +
  916. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  917. " <div class=\"ml-1 mb-0\">Double Edged Sword L." + iDELevel.toFixed(0) + "</div>\r\n" +
  918. " <small class=\"mx-3\">" + dDEDamage.toFixed(0) + " damage vs. 0 armor</small>\r\n" +
  919. " </div>\r\n" +
  920. " </div>\r\n" +
  921. " </div>\r\n";
  922.  
  923. sDESkillHTML_zerk =
  924. " <div class=\"d-flex flex-wrap\">\r\n" +
  925. " <div class=\"mb-3 mr-3\">\r\n" +
  926. " <div class=\"d-flex align-items-center\">\r\n" +
  927. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  928. " <div class=\"ml-1 mb-0\">Double Edged Sword L." + iDELevel.toFixed(0) + "</div>\r\n" +
  929. " <small class=\"mx-3\">" + dDEDamage_zerk.toFixed(0) + " (+ Berserk L." + iZerkLevel.toFixed(0) + ")</small>\r\n" +
  930. " </div>\r\n" +
  931. " </div>\r\n" +
  932. " </div>\r\n";
  933.  
  934. sDESkillHTML_zerk_WC =
  935. " <div class=\"d-flex flex-wrap\">\r\n" +
  936. " <div class=\"mb-3 mr-3\">\r\n" +
  937. " <div class=\"d-flex align-items-center\">\r\n" +
  938. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  939. " <div class=\"ml-1 mb-0\">Double Edged Sword L." + iDELevel.toFixed(0) + "</div>\r\n" +
  940. " <small class=\"mx-3\">" + dDEDamage_zerk_WC.toFixed(0) + " (+ Berserk L." + iZerkLevel.toFixed(0) + " +Warcry)</small>\r\n" +
  941. " </div>\r\n" +
  942. " </div>\r\n" +
  943. " </div>\r\n";
  944. }
  945.  
  946. //jQ("a.recent-battles-btn").parent().parent().before(
  947. jQ("div.lobby-container").append(
  948. "<div class=\"PeteUI_CombatStat\">\r\n" +
  949. " <div class=\"mb-1 text-muted\">Combat Stats</div>\r\n" +
  950. " <div class=\"d-flex\">" +
  951.  
  952. " <div class=\"col\">" +
  953. " <div class=\"d-flex flex-wrap\">\r\n" +
  954. " <div class=\"mb-3 mr-3\">\r\n" +
  955. " <div class=\"d-flex align-items-center\">\r\n" +
  956. " <i class=\"lilIcon-attack small-icon\"></i>\r\n" +
  957. " <div class=\"ml-1 mb-0\">Weapon Damage</div>\r\n" +
  958. " <small class=\"mx-3\">" + dDamageMin.toFixed(1) + " - " + dDamageMax.toFixed(1) + " (" + dAverageDamageAvgQuality.toFixed(1) + " average)</small>\r\n" +
  959. " </div>\r\n" +
  960. " </div>\r\n" +
  961. " </div>\r\n" +
  962. " <div class=\"d-flex flex-wrap\">\r\n" +
  963. " <div class=\"mb-3 mr-3\">\r\n" +
  964. " <div class=\"d-flex align-items-center\">\r\n" +
  965. " <i class=\"lilIcon-accuracy small-icon\"></i>\r\n" +
  966. " <div class=\"ml-1 mb-0\">Accuracy</div>\r\n" +
  967. " <small class=\"mx-3\">" + oCombatData.stats.accuracy.toFixed(1) + "</small>\r\n" +
  968. " </div>\r\n" +
  969. " </div>\r\n" +
  970. " </div>\r\n" +
  971. " <div class=\"d-flex flex-wrap\">\r\n" +
  972. " <div class=\"mb-3 mr-3\">\r\n" +
  973. " <div class=\"d-flex align-items-center\">\r\n" +
  974. " <i class=\"lilIcon-defense small-icon\"></i>\r\n" +
  975. " <div class=\"ml-1 mb-0\">Defense (Dodge)</div>\r\n" +
  976. " <small class=\"mx-3\">" + oCombatData.stats.defense.toFixed(1) + "</small>\r\n" +
  977. " </div>\r\n" +
  978. " </div>\r\n" +
  979. " </div>\r\n" +
  980. " <div class=\"d-flex flex-wrap\">\r\n" +
  981. " <div class=\"mb-3 mr-3\">\r\n" +
  982. " <div class=\"d-flex align-items-center\">\r\n" +
  983. " <i class=\"lilIcon-health small-icon\"></i>\r\n" +
  984. " <div class=\"ml-1 mb-0\">Health (Max)</div>\r\n" +
  985. " <small class=\"mx-3\">" + oCombatData.stats.healthMax.toFixed(0) + "</small>\r\n" +
  986. " </div>\r\n" +
  987. " </div>\r\n" +
  988. " </div>\r\n" +
  989. sDESkillHTML_zerk +
  990. " <div class=\"d-flex flex-wrap\">\r\n" +
  991. " <div class=\"mb-3 mr-3\">\r\n" +
  992. " <div class=\"d-flex align-items-center\">\r\n" +
  993. " <i class=\"lilIcon-magicPower small-icon\"></i>\r\n" +
  994. " <div class=\"ml-1 mb-0\">Magic Power</div>\r\n" +
  995. " <small class=\"mx-3\">" + oCombatData.stats.magicPower.toFixed(1) + "</small>\r\n" +
  996. " </div>\r\n" +
  997. " </div>\r\n" +
  998. " </div>\r\n" +
  999. " <div class=\"d-flex flex-wrap\">\r\n" +
  1000. " <div class=\"mb-3 mr-3\">\r\n" +
  1001. " <div class=\"d-flex align-items-center\">\r\n" +
  1002. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/airDart.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  1003. " <div class=\"ml-1 mb-0\">Air Dart</div>\r\n" +
  1004. " <small class=\"mx-3\">" + ((1.10 * oCombatData.stats.magicPower) + 1).toFixed(0) + " armor reduction</small>\r\n" +
  1005. " </div>\r\n" +
  1006. " </div>\r\n" +
  1007. " </div>\r\n" +
  1008. " <div class=\"d-flex flex-wrap\">\r\n" +
  1009. " <div class=\"mb-3 mr-3\">\r\n" +
  1010. " <div class=\"d-flex align-items-center\">\r\n" +
  1011. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/lightningDart.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  1012. " <div class=\"ml-1 mb-0\">Lightning Dart</div>\r\n" +
  1013. " <small class=\"mx-3\">" + ((0.90 * oCombatData.stats.magicPower) + 2).toFixed(0) + " armor reduction</small>\r\n" +
  1014. " </div>\r\n" +
  1015. " </div>\r\n" +
  1016. " </div>\r\n" +
  1017. " </div>\r\n" +
  1018.  
  1019. " <div class=\"col\">\r\n" +
  1020. " <div class=\"d-flex flex-wrap\">\r\n" +
  1021. " <div class=\"mb-3 mr-3\">\r\n" +
  1022. " <div class=\"d-flex align-items-center\">\r\n" +
  1023. " <i class=\"lilIcon-attackSpeed small-icon\"></i>\r\n" +
  1024. " <div class=\"ml-1 mb-0\">Attack Speed</div>\r\n" +
  1025. " <small class=\"mx-3\">" + Math.round(dAttackSpeed, 4).toString() + " attacks per second (" + dActualDPSAverageQuality.toFixed(1) + " DPS)</small>\r\n" +
  1026. " </div>\r\n" +
  1027. " </div>\r\n" +
  1028. " </div>\r\n" +
  1029. " <div class=\"d-flex flex-wrap\">\r\n" +
  1030. " <div class=\"mb-3 mr-3\">\r\n" +
  1031. " <div class=\"d-flex align-items-center\">\r\n" +
  1032. " <i class=\"lilIcon-criticalChance small-icon\"></i>\r\n" +
  1033. " <div class=\"ml-1 mb-0\">Critical Hit</div>\r\n" +
  1034. " <small class=\"mx-3\">" + ((oCombatData.stats.criticalChance <= 0.0) ? ("none") : (oCombatData.stats.criticalChance.toFixed(1) + "% chance to deal " + oCombatData.stats.criticalDamage.toFixed(1) + "x damage")) + "</small>\r\n" +
  1035. " </div>\r\n" +
  1036. " </div>\r\n" +
  1037. " </div>\r\n" +
  1038. " <div class=\"d-flex flex-wrap\">\r\n" +
  1039. " <div class=\"mb-3 mr-3\">\r\n" +
  1040. " <div class=\"d-flex align-items-center\">\r\n" +
  1041. " <i class=\"lilIcon-armor small-icon\"></i>\r\n" +
  1042. " <div class=\"ml-1 mb-0\">Physical Armor</div>\r\n" +
  1043. " <small class=\"mx-3\">" + oCombatData.stats.armor.toFixed(1) + " (" + ((1000-(100/(100+oCombatData.stats.armor)*1000))/10).toFixed(1) + "% physical protection)</small>\r\n" +
  1044. " </div>\r\n" +
  1045. " </div>\r\n" +
  1046. " </div>\r\n" +
  1047. sDESkillHTML +
  1048. sDESkillHTML_zerk_WC +
  1049. " <div class=\"d-flex flex-wrap\">\r\n" +
  1050. " <div class=\"mb-3 mr-3\">\r\n" +
  1051. " <div class=\"d-flex align-items-center\">\r\n" +
  1052. " <i class=\"lilIcon-magicArmor small-icon\"></i>\r\n" +
  1053. " <div class=\"ml-1 mb-0\">Magic Armor</div>\r\n" +
  1054. " <small class=\"mx-3\">" + oCombatData.stats.magicArmor.toFixed(1) + " (" + ((1000-(100/(100+oCombatData.stats.magicArmor)*1000))/10).toFixed(1) + "% magic protection)</small>\r\n" +
  1055. " </div>\r\n" +
  1056. " </div>\r\n" +
  1057. " </div>\r\n" +
  1058. " <div class=\"d-flex flex-wrap\">\r\n" +
  1059. " <div class=\"mb-3 mr-3\">\r\n" +
  1060. " <div class=\"d-flex align-items-center\">\r\n" +
  1061. " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/airBall.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" +
  1062. " <div class=\"ml-1 mb-0\">Air Ball</div>\r\n" +
  1063. " <small class=\"mx-3\">" + ((1.60 * oCombatData.stats.magicPower) + 10).toFixed(0) + " armor reduction</small>\r\n" +
  1064. " </div>\r\n" +
  1065. " </div>\r\n" +
  1066. " </div>\r\n" +
  1067. " <div class=\"d-flex flex-wrap\">\r\n" +
  1068. " <div class=\"mb-3 mr-3\">\r\n" +
  1069. " <div class=\"d-flex align-items-center\">\r\n" +
  1070. " <i class=\"lilIcon-healingPower small-icon\"></i>\r\n" +
  1071. " <div class=\"ml-1 mb-0\">Healing Power</div>\r\n" +
  1072. " <small class=\"mx-3\">" + ((oCombatData.stats.healingPower === 0.0) ? "normal (no bonus or penalty)" : ((oCombatData.stats.healingPower < 0) ? (oCombatData.stats.healingPower.toFixed(1) + "% lowered healing") : (oCombatData.stats.healingPower.toFixed(1) + "% increased healing"))) + "</small>\r\n" +
  1073. " </div>\r\n" +
  1074. " </div>\r\n" +
  1075. " </div>\r\n" +
  1076. " </div>\r\n" +
  1077.  
  1078. " </div>\r\n" +
  1079. "</div>\r\n");
  1080. }
  1081. }
  1082. /* else if ((!ET.MCMF.IsNewCombatTab()) && (jQ("div.stats-row").length > 0))
  1083. {
  1084. sBareDamageRange = CondenseSpacing(jQ(jQ("div.stats-row").find("div > div.col > div").get(0)).text().trim().replaceAll('\r', ' ').replaceAll('\n', ' '));
  1085. //console.log("Bare damage range: " + sBareDamageRange);
  1086.  
  1087. sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - ");
  1088. sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", "");
  1089.  
  1090. dDamageMin = CDbl(sDamagePartMin);
  1091. dDamageMax = CDbl(sDamagePartMax);
  1092.  
  1093. dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin;
  1094.  
  1095. sBareAttackSpeed = jQ(jQ("div.stats-row").find("div > div.col > div").get(1)).text().trim();
  1096. //console.log("Bare attack speed: " + sBareAttackSpeed);
  1097.  
  1098. dAttackSpeed = CDbl(sBareAttackSpeed);
  1099. dCriticalChance = CDbl(ET_Stat_CritChance);
  1100.  
  1101. if (dCriticalChance > 0.0)
  1102. dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); // note: not using ET_Stat_CritDamage!
  1103.  
  1104. dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed;
  1105.  
  1106. //console.log(dActualDPSAverageQuality.toFixed(1));
  1107.  
  1108. if (!isNaN(dActualDPSAverageQuality))
  1109. {
  1110. jQ(".PeteUI_CombatStat").remove();
  1111.  
  1112. jQ(jQ("div.stats-row").find("div > div.col > div").get(0)).append("<span class=\"PeteUI_CombatStat\">&nbsp;(" + dAverageDamageAvgQuality.toFixed(1) + " average)</span>");
  1113. jQ(jQ("div.stats-row").find("div > div.col > div").get(1)).append("<span class=\"PeteUI_CombatStat\">&nbsp;attacks per second (" + dActualDPSAverageQuality.toFixed(1) + " DPS)</span>");
  1114. jQ(jQ("div.stats-row").find("div > div.col > div").get(2)).append("<span class=\"PeteUI_CombatStat\">&nbsp;magic power</span>");
  1115. jQ(jQ("div.stats-row").find("div > div.col > div").get(3)).append("<span class=\"PeteUI_CombatStat\">&nbsp;accuracy</span>");
  1116. jQ(jQ("div.stats-row").find("div > div.col > div").get(4)).append("<span class=\"PeteUI_CombatStat\">&nbsp;health</span>");
  1117. jQ(jQ("div.stats-row").find("div > div.col > div").get(5)).append("<span class=\"PeteUI_CombatStat\">&nbsp;dodge (defense)</span>");
  1118. jQ(jQ("div.stats-row").find("div > div.col > div").get(6)).append("<span class=\"PeteUI_CombatStat\">&nbsp;physical armor</span>");
  1119. jQ(jQ("div.stats-row").find("div > div.col > div").get(7)).append("<span class=\"PeteUI_CombatStat\">&nbsp;magic armor</span>");
  1120.  
  1121. if (CDbl(ET_Stat_CritChance) > 0.0)
  1122. jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/criticalChance.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + ET_Stat_CritChance.toFixed(1) + " critical chance for " + ET_Stat_CritDamage + "x damage\r\n</div>\r\n");
  1123. else
  1124. jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/criticalChance.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\nno critical chance\r\n</div>\r\n");
  1125.  
  1126. if (CDbl(ET_Stat_HealingPower) !== 0.0)
  1127. jQ(jQ("div.stats-row").find("div > div.col").get(1)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/healingPower.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + ET_Stat_HealingPower.toFixed(1) + "% " + ((CDbl(ET_Stat_HealingPower) > 0.0) ? "increased" : "lowered") + " healing\r\n</div>\r\n");
  1128. else
  1129. jQ(jQ("div.stats-row").find("div > div.col").get(1)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/healingPower.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\nnormal healing\r\n</div>\r\n");
  1130.  
  1131. //jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + (dDamageMax * 1.5 * 1.7 * 2.5 * 5.0).toFixed(0) + " DE damage vs. 0 armor\r\n</div>\r\n");
  1132. //jQ(jQ("div.stats-row").find("div > div.col").get(1)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center ml-1\">\r\n(using demon curse, war cry, and berserk)\r\n</div>\r\n");
  1133. jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/doubleEdgedSword.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + (dDamageMax * 1.5 * 1.7 * 5.0).toFixed(0) + " DE damage vs. 0 armor\r\n</div>\r\n");
  1134. jQ(jQ("div.stats-row").find("div > div.col").get(1)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center ml-1\">\r\n(using L.5 war cry, berserk, and DE)\r\n</div>\r\n");
  1135. jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/airDart.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + ((1.10 * ET_Stat_MP) + 1).toFixed(0) + " air dart armor reduction\r\n</div>\r\n");
  1136. jQ(jQ("div.stats-row").find("div > div.col").get(1)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/airBall.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + ((1.60 * ET_Stat_MP) + 10).toFixed(0) + " air ball armor reduction\r\n</div>\r\n");
  1137. jQ(jQ("div.stats-row").find("div > div.col").get(0)).append("<div class=\"d-flex flex-row mb-1 PeteUI_CombatStat\">\r\n<div class=\"d-flex align-items-center attack-tooltip-container drop-target drop-abutted drop-abutted-left drop-abutted-top drop-element-attached-bottom drop-element-attached-left drop-target-attached-top drop-target-attached-left\">\r\n<img src=\"/icons/lightningDart.svg\" class=\"extra-small-icon\">\r\n</div>\r\n<div class=\"d-flex align-items-center ml-1\">\r\n" + ((0.90 * ET_Stat_MP) + 2).toFixed(0) + " lightning dart armor reduction\r\n</div>\r\n");
  1138. }
  1139. }
  1140. */
  1141. }
  1142. }
  1143. catch (err) { ET.MCMF.Log("Error in Stats mod rendering extra combat stats:"); console.log(err); }
  1144. //
  1145. ///////////////////////////////////////////////////////////////////////////////////////
  1146.  
  1147. setTimeout(ET_StatsUIMod_DPSShow, 1000);
  1148. };
  1149.  
  1150.  
  1151. ////////////////////////////////////////////////////////////////
  1152. /////////////// ** common.js -- DO NOT MODIFY ** ///////////////
  1153. time_val = function()
  1154. {
  1155. return CDbl(Math.floor(Date.now() / 1000));
  1156. };
  1157.  
  1158. IsValid = function(oObject)
  1159. {
  1160. if (oObject === undefined) return false;
  1161. if (oObject === null) return false;
  1162. return true;
  1163. };
  1164.  
  1165. const CommonRandom = function(iMin, iMax)
  1166. {
  1167. return parseInt(iMin + Math.floor(Math.random() * iMax));
  1168. };
  1169.  
  1170. ShiftClick = function(oEl)
  1171. {
  1172. jQ(oEl).trigger(ShiftClickEvent());
  1173. };
  1174.  
  1175. ShiftClickEvent = function(target)
  1176. {
  1177. let shiftclickOrig = jQ.Event("click");
  1178. shiftclickOrig.which = 1; // 1 = left, 2 = middle, 3 = right
  1179. //shiftclickOrig.type = "click"; // "mousedown" ?
  1180. shiftclickOrig.shiftKey = true;
  1181. shiftclickOrig.currentTarget = target;
  1182.  
  1183. let shiftclick = jQ.Event("click");
  1184. shiftclick.which = 1; // 1 = left, 2 = middle, 3 = right
  1185. //shiftclick.type = "click"; // "mousedown" ?
  1186. shiftclick.shiftKey = true;
  1187. shiftclick.currentTarget = target;
  1188.  
  1189. shiftclick.originalEvent = shiftclickOrig;
  1190.  
  1191. //document.ET_Util_Log(shiftclick);
  1192.  
  1193. return shiftclick;
  1194. };
  1195.  
  1196. if (!String.prototype.replaceAll)
  1197. String.prototype.replaceAll = function(search, replace) { return ((replace === undefined) ? this.toString() : this.replace(new RegExp('[' + search + ']', 'g'), replace)); };
  1198.  
  1199. if (!String.prototype.startsWith)
  1200. String.prototype.startsWith = function(search, pos) { return this.substr(((!pos) || (pos < 0)) ? 0 : +pos, search.length) === search; };
  1201.  
  1202. CInt = function(v)
  1203. {
  1204. try
  1205. {
  1206. if (!isNaN(v)) return Math.floor(v);
  1207. if (typeof v === 'undefined') return parseInt(0);
  1208. if (v === null) return parseInt(0);
  1209. let t = parseInt(v);
  1210. if (isNaN(t)) return parseInt(0);
  1211. return Math.floor(t);
  1212. }
  1213. catch (err) { }
  1214.  
  1215. return parseInt(0);
  1216. };
  1217.  
  1218. CDbl = function(v)
  1219. {
  1220. try
  1221. {
  1222. if (!isNaN(v)) return parseFloat(v);
  1223. if (typeof v === 'undefined') return parseFloat(0.0);
  1224. if (v === null) return parseFloat(0.0);
  1225. let t = parseFloat(v);
  1226. if (isNaN(t)) return parseFloat(0.0);
  1227. return t;
  1228. }
  1229. catch (err) { }
  1230.  
  1231. return parseFloat(0.0);
  1232. };
  1233.  
  1234. // dup of String.prototype.startsWith, but uses indexOf() instead of substr()
  1235. startsWith = function (haystack, needle) { return (needle === "") || (haystack.indexOf(needle) === 0); };
  1236. endsWith = function (haystack, needle) { return (needle === "") || (haystack.substring(haystack.length - needle.length) === needle); };
  1237.  
  1238. Chopper = function(sText, sSearch, sEnd)
  1239. {
  1240. let sIntermediate = "";
  1241.  
  1242. if (sSearch === "")
  1243. sIntermediate = sText.substring(0, sText.length);
  1244. else
  1245. {
  1246. let iIndexStart = sText.indexOf(sSearch);
  1247. if (iIndexStart === -1)
  1248. return sText;
  1249.  
  1250. sIntermediate = sText.substring(iIndexStart + sSearch.length);
  1251. }
  1252.  
  1253. if (sEnd === "")
  1254. return sIntermediate;
  1255.  
  1256. let iIndexEnd = sIntermediate.indexOf(sEnd);
  1257.  
  1258. return (iIndexEnd === -1) ? sIntermediate : sIntermediate.substring(0, iIndexEnd);
  1259. };
  1260.  
  1261. ChopperBlank = function(sText, sSearch, sEnd)
  1262. {
  1263. let sIntermediate = "";
  1264.  
  1265. if (sSearch === "")
  1266. sIntermediate = sText.substring(0, sText.length);
  1267. else
  1268. {
  1269. let iIndexStart = sText.indexOf(sSearch);
  1270. if (iIndexStart === -1)
  1271. return "";
  1272.  
  1273. sIntermediate = sText.substring(iIndexStart + sSearch.length);
  1274. }
  1275.  
  1276. if (sEnd === "")
  1277. return sIntermediate;
  1278.  
  1279. let iIndexEnd = sIntermediate.indexOf(sEnd);
  1280.  
  1281. return (iIndexEnd === -1) ? "" : sIntermediate.substring(0, iIndexEnd);
  1282. };
  1283.  
  1284. CondenseSpacing = function(text)
  1285. {
  1286. while (text.indexOf(" ") !== -1)
  1287. text = text.replace(" ", " ");
  1288. return text;
  1289. };
  1290.  
  1291. // pad available both ways as pad(string, width, [char]) or string.pad(width, [char])
  1292. pad = function(sText, iWidth, sChar)
  1293. {
  1294. sChar = ((sChar !== undefined) ? sChar : ('0'));
  1295. sText = sText.toString();
  1296. return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText));
  1297. };
  1298.  
  1299. if (!String.prototype.pad)
  1300. String.prototype.pad = function(iWidth, sChar)
  1301. {
  1302. sChar = ((sChar !== undefined) ? sChar : ('0'));
  1303. sText = sText.toString();
  1304. return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText));
  1305. };
  1306.  
  1307. String.prototype.toHHMMSS = function () {
  1308. let sec_num = parseInt(this, 10);
  1309. let hours = Math.floor(sec_num / 3600);
  1310. let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
  1311. let seconds = sec_num - (hours * 3600) - (minutes * 60);
  1312.  
  1313. if (hours < 10) {hours = "0"+hours;}
  1314. if (minutes < 10) {minutes = "0"+minutes;}
  1315. if (seconds < 10) {seconds = "0"+seconds;}
  1316. return hours+':'+minutes+':'+seconds;
  1317. };
  1318.  
  1319. String.prototype.toFriendlyTime = function () {
  1320. let sec_num = parseInt(this, 10);
  1321. let hours = Math.floor(sec_num / 3600);
  1322. let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
  1323. let seconds = sec_num - (hours * 3600) - (minutes * 60);
  1324.  
  1325. let out = '';
  1326.  
  1327. if (hours > 0) out = `${out}${hours}h`;
  1328. if (minutes > 0) out = `${out}${minutes}m`;
  1329. if (seconds > 0) out = `${out}${seconds}s`;
  1330. return out;
  1331. };
  1332.  
  1333. Number.prototype.toPercent = function () {
  1334. try
  1335. {
  1336. let pct_val = parseFloat(this);
  1337. if (pct_val >= 15.0) return pct_val.toFixed(0);
  1338. return pct_val.toFixed(1).replace(".0", "");
  1339. }
  1340. catch (err) { }
  1341. return 'NaN';
  1342. };
  1343.  
  1344. is_visible = (function () {
  1345. let x = window.pageXOffset ? window.pageXOffset + window.innerWidth - 1 : 0,
  1346. y = window.pageYOffset ? window.pageYOffset + window.innerHeight - 1 : 0,
  1347. relative = !!((!x && !y) || !document.elementFromPoint(x, y));
  1348. function inside(child, parent) {
  1349. while(child){
  1350. if (child === parent) return true;
  1351. child = child.parentNode;
  1352. }
  1353. return false;
  1354. }
  1355. return function (elem) {
  1356. if (
  1357. hidden ||
  1358. elem.offsetWidth==0 ||
  1359. elem.offsetHeight==0 ||
  1360. elem.style.visibility=='hidden' ||
  1361. elem.style.display=='none' ||
  1362. elem.style.opacity===0
  1363. ) return false;
  1364. let rect = elem.getBoundingClientRect();
  1365. if (relative) {
  1366. if (!inside(document.elementFromPoint(rect.left + elem.offsetWidth/2, rect.top + elem.offsetHeight/2),elem)) return false;
  1367. } else if (
  1368. !inside(document.elementFromPoint(rect.left + elem.offsetWidth/2 + window.pageXOffset, rect.top + elem.offsetHeight/2 + window.pageYOffset), elem) ||
  1369. (
  1370. rect.top + elem.offsetHeight/2 < 0 ||
  1371. rect.left + elem.offsetWidth/2 < 0 ||
  1372. rect.bottom - elem.offsetHeight/2 > (window.innerHeight || document.documentElement.clientHeight) ||
  1373. rect.right - elem.offsetWidth/2 > (window.innerWidth || document.documentElement.clientWidth)
  1374. )
  1375. ) return false;
  1376. if (window.getComputedStyle || elem.currentStyle) {
  1377. let el = elem,
  1378. comp = null;
  1379. while (el) {
  1380. if (el === document) {break;} else if(!el.parentNode) return false;
  1381. comp = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
  1382. if (comp && (comp.visibility=='hidden' || comp.display == 'none' || (typeof comp.opacity !=='undefined' && comp.opacity != 1))) return false;
  1383. el = el.parentNode;
  1384. }
  1385. }
  1386. return true;
  1387. };
  1388. })();
  1389.  
  1390. function sumObjectsByKey(...objs) {
  1391. return objs.reduce((a, b) => {
  1392. for (let k in b) {
  1393. if (b.hasOwnProperty(k))
  1394. a[k] = (a[k] || 0) + b[k];
  1395. }
  1396. return a;
  1397. }, {});
  1398. }
  1399. ////////////////////////////////////////////////////////////////
  1400.  
  1401.  
  1402. ////////////////////////////////////////////////////////////////
  1403. ////////////// ** common_ET.js -- DO NOT MODIFY ** /////////////
  1404. if (window.ET === undefined) window.ET = { };
  1405. if ((window.ET.MCMF === undefined) || (CDbl(window.ET.MCMF.version) < 1.08)) // MeanCloud mod framework
  1406. {
  1407. window.ET.MCMF =
  1408. {
  1409. version: 1.08,
  1410.  
  1411. TryingToLoad: false,
  1412. WantDebug: false,
  1413. WantFasterAbilityCDs: false,
  1414.  
  1415. InBattle: false,
  1416. FinishedLoading: false,
  1417. Initialized: false,
  1418. AbilitiesReady: false,
  1419. InitialAbilityCheck: true,
  1420. TimeLeftOnCD: 9999,
  1421. TimeLastFight: 0,
  1422.  
  1423. ToastMessageSuccess: function(msg)
  1424. {
  1425. toastr.success(msg);
  1426. },
  1427.  
  1428. ToastMessageWarning: function(msg)
  1429. {
  1430. toastr.warning(msg);
  1431. },
  1432.  
  1433. EventSubscribe: function(sEventName, fnCallback, sNote)
  1434. {
  1435. if (window.ET.MCMF.EventSubscribe_events === undefined)
  1436. window.ET.MCMF.EventSubscribe_events = [];
  1437.  
  1438. let newEvtData = {};
  1439. newEvtData.name = ((!sEventName.startsWith("ET:")) ? (`ET:${sEventName}`) : (sEventName));
  1440. newEvtData.callback = fnCallback;
  1441. newEvtData.note = sNote;
  1442.  
  1443. window.ET.MCMF.EventSubscribe_events.push(newEvtData);
  1444.  
  1445. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Added event subscription '${sEventName}'!` + ((sNote === undefined) ? "" : ` (${sNote})`));
  1446. },
  1447.  
  1448. EventTrigger: function(sEventName)
  1449. {
  1450. if (window.ET.MCMF.EventSubscribe_events === undefined) return;
  1451.  
  1452. window.ET.MCMF.EventSubscribe_events.forEach(function(oThisEvent)
  1453. {
  1454. if (sEventName === oThisEvent.name)
  1455. {
  1456. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`FIRING '${oThisEvent.name}'!` + ((oThisEvent.note === undefined) ? "" : ` (${oThisEvent.note})`));
  1457. try { oThisEvent.callback(); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Exception:"); console.log(err); }
  1458. }
  1459. });
  1460. },
  1461.  
  1462. Log: function(msg)
  1463. {
  1464. try
  1465. {
  1466. let now = new Date();
  1467. let timestamp_date = `${(now.getMonth()+1)}/${now.getDate()}`;
  1468. let timestamp_time = `${((now.getHours()===0)?12:((now.getHours()>12)?(now.getHours()-12):(now.getHours())))}:${now.getMinutes().toString().padStart(2,"0")}:${now.getSeconds().toString().padStart(2,"0")}${((now.getHours()< 2)?"a":"p")}`;
  1469. console.log(`%c${timestamp_date} ${timestamp_time}%c ${msg}`, "color: #555;", "font-weight: bold;");
  1470. }
  1471. catch (err) { }
  1472. },
  1473.  
  1474. Time: function() // returns time in milliseconds (not seconds!)
  1475. {
  1476. return CInt((new Date()).getTime());
  1477. },
  1478.  
  1479. SubscribeToGameChannel: function(channel_name)
  1480. {
  1481. let oChannel;
  1482.  
  1483. try
  1484. {
  1485. channel_name = channel_name.toString().trim();
  1486.  
  1487. let bAlreadySubscribed = false;
  1488.  
  1489. jQuery.makeArray(Object.keys(Meteor.connection._subscriptions).map(key => Meteor.connection._subscriptions[key])).forEach(function(oThisConnection)
  1490. {
  1491. try
  1492. {
  1493. if (oThisConnection.name === channel_name)
  1494. bAlreadySubscribed = true;
  1495. }
  1496. catch (err) { }
  1497. });
  1498.  
  1499. if (!bAlreadySubscribed)
  1500. {
  1501. Meteor.subscribe(channel_name);
  1502. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Meteor::Subscribed to channel '${channel_name}'`);
  1503. }
  1504. }
  1505. catch (err)
  1506. {
  1507. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Meteor::Exception in SubscribeToGameChannel("${channel_name}"):`);
  1508. if (window.ET.MCMF.WantDebug) console.log(err);
  1509. }
  1510.  
  1511. return oChannel;
  1512. },
  1513.  
  1514. CraftingBuff: function()
  1515. {
  1516. let oDate, iTimeLeft;
  1517.  
  1518. try
  1519. {
  1520. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffCrafting" }).fetch()[0].value.activeTo);
  1521. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  1522.  
  1523. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  1524. }
  1525. catch (err) { }
  1526.  
  1527. return { active: false, remaining: 0, expires: oDate };
  1528. },
  1529.  
  1530. CombatBuff: function()
  1531. {
  1532. let oDate, iTimeLeft;
  1533.  
  1534. try
  1535. {
  1536. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffCombat" }).fetch()[0].value.activeTo);
  1537. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  1538.  
  1539. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  1540. }
  1541. catch (err) { }
  1542.  
  1543. return { active: false, remaining: 0, expires: oDate };
  1544. },
  1545.  
  1546. GatheringBuff: function()
  1547. {
  1548. let oDate, iTimeLeft;
  1549.  
  1550. try
  1551. {
  1552. oDate = new Date(Meteor.connection._stores.state._getCollection().find({ name: "buffGathering" }).fetch()[0].value.activeTo);
  1553. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  1554.  
  1555. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  1556. }
  1557. catch (err) { }
  1558.  
  1559. return { active: false, remaining: 0, expires: oDate };
  1560. },
  1561.  
  1562. PersonalCraftingBuff: function()
  1563. {
  1564. let oDate, iTimeLeft;
  1565.  
  1566. try
  1567. {
  1568. oDate = new Date(Meteor.connection._stores.users._getCollection().find().fetch()[0].craftingUpgradeTo);
  1569. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  1570.  
  1571. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  1572. }
  1573. catch (err) { }
  1574.  
  1575. return { active: false, remaining: 0, expires: oDate };
  1576. },
  1577.  
  1578. PersonalWoodcuttingBuff: function()
  1579. {
  1580. let oDate, iTimeLeft;
  1581.  
  1582. try
  1583. {
  1584. oDate = new Date(Meteor.connection._stores.users._getCollection().find().fetch()[0].woodcuttingUpgradeTo);
  1585. iTimeLeft = ((oDate) > (new Date())) ? CInt(Math.floor(Math.abs(oDate - (new Date())) / 1000.0)) : 0;
  1586.  
  1587. return { active: (iTimeLeft > 0), remaining: iTimeLeft, expires: oDate };
  1588. }
  1589. catch (err) { }
  1590.  
  1591. return { active: false, remaining: 0, expires: oDate };
  1592. },
  1593.  
  1594. // pretty much always true now since the routes changed (/combat and /newCombat are both the same page)
  1595. IsNewCombatTab: function() {
  1596. try {
  1597. const routeName = Router._currentRoute.getName();
  1598. const windowUrl = window.location.href;
  1599.  
  1600. if ((routeName === 'battle') || (routeName === 'combat') || (routeName === 'newCombat') || (routeName === 'fight')) {
  1601. return true;
  1602. }
  1603.  
  1604. if ((windowUrl.indexOf('/battle') !== -1) || (windowUrl.indexOf('/combat') !== -1) || (windowUrl.indexOf('/newCombat') !== -1) || (windowUrl.indexOf('/fight') !== -1)) {
  1605. return true;
  1606. }
  1607. } catch (err) {
  1608. }
  1609.  
  1610. return false;
  1611. },
  1612.  
  1613. GetActiveTab: function()
  1614. {
  1615. let active_tab = "";
  1616. let current_route = Router._currentRoute.getName();
  1617.  
  1618. if ((current_route === "overview") || (current_route === "gameHome")) active_tab = "home";
  1619. if ((current_route === "mine") || (current_route === "mining") || (current_route === "minePit")) active_tab = "mining";
  1620. if ((current_route === "items") || (current_route === "inventory") || (current_route === "craft") || (current_route === "crafting")) active_tab = "crafting";
  1621. if ((current_route === "battle") || (current_route === "combat") || (current_route === "newCombat") || (current_route === "fight")) active_tab = "combat";
  1622. if ((current_route === "woodcut") || (current_route === "woodcutting") || (current_route === "lumber") || (current_route === "lumbering")) active_tab = "woodcutting";
  1623. if ((current_route === "farm") || (current_route === "farming")) active_tab = "farming";
  1624. if ((current_route === "inscribe") || (current_route === "inscribing") || (current_route === "inscription") || (current_route === "enchantments") || (current_route === "alchemy")) active_tab = "inscription";
  1625. if ((current_route === "magic") || (current_route === "astro") || (current_route === "astrology") || (current_route === "astronomy") || (current_route === "spells") || (current_route === "spellBook")) active_tab = "magic";
  1626. if ((current_route === "faq") || (current_route === "help")) active_tab = "faq";
  1627. if (current_route === "chat") active_tab = "chat";
  1628. if ((current_route === "skills") || (current_route === "leaderboard") || (current_route === "ranking") || (current_route === "ranks")) active_tab = "skills";
  1629. if (current_route === "achievements") active_tab = "achievements";
  1630. if ((current_route === "updates") || (current_route === "patchNotes") || (current_route === "changelog") || (current_route === "changes") || (current_route === "news")) active_tab = "updates";
  1631.  
  1632. if (active_tab === "") {
  1633. if (window.location.href.indexOf("/gameHome") !== -1) active_tab = "home";
  1634. if (window.location.href.indexOf("/overview") !== -1) active_tab = "home";
  1635. if (window.location.href.indexOf("/mine") !== -1) active_tab = "mining";
  1636. if (window.location.href.indexOf("/mining") !== -1) active_tab = "mining";
  1637. if (window.location.href.indexOf("/minePit") !== -1) active_tab = "mining";
  1638. if (window.location.href.indexOf("/items") !== -1) active_tab = "crafting";
  1639. if (window.location.href.indexOf("/inventory") !== -1) active_tab = "crafting";
  1640. if (window.location.href.indexOf("/craft") !== -1) active_tab = "crafting";
  1641. if (window.location.href.indexOf("/crafting") !== -1) active_tab = "crafting";
  1642. if (window.location.href.indexOf("/battle") !== -1) active_tab = "combat";
  1643. if (window.location.href.indexOf("/combat") !== -1) active_tab = "combat";
  1644. if (window.location.href.indexOf("/newCombat") !== -1) active_tab = "combat";
  1645. if (window.location.href.indexOf("/fight") !== -1) active_tab = "combat";
  1646. if (window.location.href.indexOf("/woodcut") !== -1) active_tab = "woodcutting";
  1647. if (window.location.href.indexOf("/woodcutting") !== -1) active_tab = "woodcutting";
  1648. if (window.location.href.indexOf("/lumber") !== -1) active_tab = "woodcutting";
  1649. if (window.location.href.indexOf("/lumbering") !== -1) active_tab = "woodcutting";
  1650. if (window.location.href.indexOf("/farm") !== -1) active_tab = "farming";
  1651. if (window.location.href.indexOf("/farming") !== -1) active_tab = "farming";
  1652. if (window.location.href.indexOf("/inscribe") !== -1) active_tab = "inscription";
  1653. if (window.location.href.indexOf("/inscribing") !== -1) active_tab = "inscription";
  1654. if (window.location.href.indexOf("/inscription") !== -1) active_tab = "inscription";
  1655. if (window.location.href.indexOf("/enchantments") !== -1) active_tab = "inscription";
  1656. if (window.location.href.indexOf("/alchemy") !== -1) active_tab = "inscription";
  1657. if (window.location.href.indexOf("/magic") !== -1) active_tab = "magic";
  1658. if (window.location.href.indexOf("/astro") !== -1) active_tab = "magic";
  1659. if (window.location.href.indexOf("/astrology") !== -1) active_tab = "magic";
  1660. if (window.location.href.indexOf("/astronomy") !== -1) active_tab = "magic";
  1661. if (window.location.href.indexOf("/spells") !== -1) active_tab = "magic";
  1662. if (window.location.href.indexOf("/spellBook") !== -1) active_tab = "magic";
  1663. if (window.location.href.indexOf("/faq") !== -1) active_tab = "faq";
  1664. if (window.location.href.indexOf("/help") !== -1) active_tab = "faq";
  1665. if (window.location.href.indexOf("/chat") !== -1) active_tab = "chat";
  1666. if (window.location.href.indexOf("/skills") !== -1) active_tab = "skills";
  1667. if (window.location.href.indexOf("/leaderboard") !== -1) active_tab = "skills";
  1668. if (window.location.href.indexOf("/ranking") !== -1) active_tab = "skills";
  1669. if (window.location.href.indexOf("/ranks") !== -1) active_tab = "skills";
  1670. if (window.location.href.indexOf("/achievements") !== -1) active_tab = "achievements";
  1671. if (window.location.href.indexOf("/updates") !== -1) active_tab = "updates";
  1672. if (window.location.href.indexOf("/patchNotes") !== -1) active_tab = "updates";
  1673. if (window.location.href.indexOf("/changelog") !== -1) active_tab = "updates";
  1674. if (window.location.href.indexOf("/changes") !== -1) active_tab = "updates";
  1675. if (window.location.href.indexOf("/news") !== -1) active_tab = "updates";
  1676. }
  1677.  
  1678. return active_tab;
  1679. },
  1680.  
  1681. GetActiveTabSection: function()
  1682. {
  1683. let active_tab_section = "";
  1684.  
  1685. try
  1686. {
  1687. let active_tab = window.ET.MCMF.GetActiveTab();
  1688.  
  1689. if (active_tab === "mining") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.miningTab;
  1690. if (active_tab === "crafting") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.craftingFilter;
  1691. if (active_tab === "combat")
  1692. {
  1693. if (window.ET.MCMF.IsNewCombatTab())
  1694. active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.newCombatType;
  1695. else
  1696. active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.combatTab;
  1697. }
  1698. if (active_tab === "farming") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.farmingTab;
  1699. if (active_tab === "inscription") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.inscriptionFilter;
  1700. if (active_tab === "achievements") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.achievementTab;
  1701. if (active_tab === "magic") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.magicTab;
  1702.  
  1703. active_tab_section = active_tab_section.trim().toLowerCase();
  1704.  
  1705. if (active_tab_section === "minepit") active_tab_section = "mine pit";
  1706. if (active_tab_section === "personalquest") active_tab_section = "personal quest";
  1707. if (active_tab_section === "tower") active_tab_section = "the tower";
  1708. if (active_tab_section === "battlelog") active_tab_section = "battle log";
  1709. if (active_tab_section === "pigment") active_tab_section = "pigments";
  1710. if (active_tab_section === "book") active_tab_section = "books";
  1711. if (active_tab_section === "magic_book") active_tab_section = "magic books";
  1712. if (active_tab_section === "spellbook") active_tab_section = "spell book";
  1713.  
  1714. if (active_tab_section.length === 0)
  1715. throw "Invalid active tab section";
  1716. }
  1717. catch (err)
  1718. {
  1719. try
  1720. {
  1721. active_tab_section = jQuery(jQuery("a.active").get(1)).text().trim().toLowerCase();
  1722.  
  1723. if (active_tab_section.length === 0)
  1724. throw "Invalid active tab section";
  1725. }
  1726. catch (err) { }
  1727. }
  1728.  
  1729. return active_tab_section;
  1730. },
  1731.  
  1732. BattleSocket_UseAbility: function(abil, targ)
  1733. {
  1734. try
  1735. {
  1736. let sMsg = '';
  1737.  
  1738. if (targ === undefined)
  1739. {
  1740. sMsg = '["action",{"abilityId":"' + abil + '","targets":[],"caster":"' + window.ET.MCMF.UserID + '"}]';
  1741. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Battle socket emitting: '${sMsg}'`);
  1742.  
  1743. battleSocket.emit
  1744. (
  1745. "action",
  1746. {
  1747. abilityId: abil,
  1748. targets: [],
  1749. caster: window.ET.MCMF.UserID
  1750. }
  1751. );
  1752. }
  1753. else
  1754. {
  1755. sMsg = '["action",{"abilityId":"' + abil + '","targets":["' + targ + '"],"caster":"' + window.ET.MCMF.UserID + '"}]';
  1756. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Battle socket emitting: '${sMsg}'`);
  1757.  
  1758. battleSocket.emit
  1759. (
  1760. "action",
  1761. {
  1762. abilityId: abil,
  1763. targets: [targ],
  1764. caster: window.ET.MCMF.UserID
  1765. }
  1766. );
  1767. }
  1768. }
  1769. catch (err) { }
  1770. },
  1771.  
  1772. CallGameCmd: function()
  1773. {
  1774. try
  1775. {
  1776. if (arguments.length > 0)
  1777. {
  1778. let cmd = arguments[0];
  1779. let fnc = function() { };
  1780.  
  1781. if (arguments.length === 1)
  1782. {
  1783. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with no data`);
  1784. Package.meteor.Meteor.call(cmd, fnc);
  1785. }
  1786. else
  1787. {
  1788. let data1, data2, data3, data4;
  1789.  
  1790. if (typeof arguments[arguments.length - 1] === "function")
  1791. {
  1792. fnc = arguments[arguments.length - 1];
  1793. if (arguments.length >= 3) data1 = arguments[1];
  1794. if (arguments.length >= 4) data2 = arguments[2];
  1795. if (arguments.length >= 5) data3 = arguments[3];
  1796. if (arguments.length >= 6) data4 = arguments[4];
  1797. }
  1798. else
  1799. {
  1800. if (arguments.length >= 2) data1 = arguments[1];
  1801. if (arguments.length >= 3) data2 = arguments[2];
  1802. if (arguments.length >= 4) data3 = arguments[3];
  1803. if (arguments.length >= 5) data4 = arguments[4];
  1804. }
  1805.  
  1806. if (data1 === undefined)
  1807. {
  1808. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with no data`);
  1809. Package.meteor.Meteor.call(cmd, fnc);
  1810. }
  1811. else if (data2 === undefined)
  1812. {
  1813. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with { ${JSON.stringify(data1)} }`);
  1814. Package.meteor.Meteor.call(cmd, data1, fnc);
  1815. }
  1816. else if (data3 === undefined)
  1817. {
  1818. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with { ${JSON.stringify(data1)}, ${JSON.stringify(data2)} }`);
  1819. Package.meteor.Meteor.call(cmd, data1, data2, fnc);
  1820. }
  1821. else if (data4 === undefined)
  1822. {
  1823. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with { ${JSON.stringify(data1)}, ${JSON.stringify(data2)}, ${JSON.stringify(data3)} }`);
  1824. Package.meteor.Meteor.call(cmd, data1, data2, data3, fnc);
  1825. }
  1826. else
  1827. {
  1828. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Calling: '${cmd}' with { ${JSON.stringify(data1)}, ${JSON.stringify(data2)}, ${JSON.stringify(data3)}, ${JSON.stringify(data4)} }`);
  1829. Package.meteor.Meteor.call(cmd, data1, data2, data3, data4, fnc);
  1830. }
  1831. }
  1832. }
  1833. else if (window.ET.MCMF.WantDebug)
  1834. window.ET.MCMF.Log("Meteor::Warning, CallGameCmd() with no arguments!");
  1835. }
  1836. catch (err)
  1837. {
  1838. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in CallGameCmd():");
  1839. if (window.ET.MCMF.WantDebug) console.log(err);
  1840. }
  1841. },
  1842.  
  1843. SendGameCmd: function(cmd)
  1844. {
  1845. try
  1846. {
  1847. Meteor.connection._send(cmd);
  1848. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Meteor::Sending: ${JSON.stringify(cmd)}`);
  1849. }
  1850. catch (err)
  1851. {
  1852. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`Meteor::Exception in SendGameCmd(${JSON.stringify(cmd)}):`);
  1853. if (window.ET.MCMF.WantDebug) console.log(err);
  1854. }
  1855. },
  1856.  
  1857. FasterAbilityUpdates: function()
  1858. {
  1859. try
  1860. {
  1861. window.ET.MCMF.SubscribeToGameChannel("abilities");
  1862.  
  1863. if ((window.ET.MCMF.WantFasterAbilityCDs) && (window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.InBattle) && (!window.ET.MCMF.AbilitiesReady))
  1864. window.ET.MCMF.CallGameCmd("abilities.gameUpdate");
  1865. }
  1866. catch (err) { }
  1867.  
  1868. setTimeout(window.ET.MCMF.FasterAbilityUpdates, 2000);
  1869. },
  1870.  
  1871. PlayerInCombat: function()
  1872. {
  1873. return ((window.ET.MCMF.InBattle) || ((window.ET.MCMF.Time() - window.ET.MCMF.TimeLastFight) < 3));
  1874. },
  1875.  
  1876. AbilityCDTrigger: function()
  1877. {
  1878. try
  1879. {
  1880. if ((window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.PlayerInCombat()))
  1881. {
  1882. iTotalCD = 0;
  1883. iTotalCDTest = 0;
  1884. iHighestCD = 0;
  1885.  
  1886. window.ET.MCMF.GetAbilities().forEach(function(oThisAbility)
  1887. {
  1888. if (oThisAbility.equipped)
  1889. {
  1890. if (parseInt(oThisAbility.currentCooldown) > 0)
  1891. {
  1892. iTotalCD += parseInt(oThisAbility.currentCooldown);
  1893. if (iHighestCD < parseInt(oThisAbility.currentCooldown))
  1894. iHighestCD = parseInt(oThisAbility.currentCooldown);
  1895. }
  1896. }
  1897.  
  1898. iTotalCDTest += parseInt(oThisAbility.cooldown);
  1899. });
  1900.  
  1901. if ((iTotalCDTest > 0) && (iTotalCD === 0))
  1902. {
  1903. if (!window.ET.MCMF.AbilitiesReady)
  1904. {
  1905. if (!window.ET.MCMF.InitialAbilityCheck)
  1906. {
  1907. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->");
  1908. window.ET.MCMF.EventTrigger("ET:abilitiesReady");
  1909. }
  1910. }
  1911.  
  1912. window.ET.MCMF.AbilitiesReady = true;
  1913. window.ET.MCMF.TimeLeftOnCD = 0;
  1914. }
  1915. else
  1916. {
  1917. window.ET.MCMF.AbilitiesReady = false;
  1918. window.ET.MCMF.TimeLeftOnCD = iHighestCD;
  1919. }
  1920.  
  1921. window.ET.MCMF.InitialAbilityCheck = false;
  1922. }
  1923. else
  1924. {
  1925. window.ET.MCMF.AbilitiesReady = false;
  1926. window.ET.MCMF.TimeLeftOnCD = 9999;
  1927. }
  1928. }
  1929. catch (err) { }
  1930.  
  1931. setTimeout(window.ET.MCMF.AbilityCDTrigger, 500);
  1932. },
  1933.  
  1934. BattleFloorRoom: "0.0",
  1935. BattleFirstFrame: undefined,
  1936. BattleUnitList: [],
  1937. BattleUITemplate: undefined,
  1938.  
  1939. LiveBattleData: function()
  1940. {
  1941. try
  1942. {
  1943. if (window.ET.MCMF.BattleUITemplate !== undefined)
  1944. return window.ET.MCMF.BattleUITemplate.state.get("currentBattle");
  1945. }
  1946. catch (err) { }
  1947.  
  1948. return undefined;
  1949. },
  1950.  
  1951. LastUnitIDList: '',
  1952. InternalBattleTickMonitor: undefined,
  1953.  
  1954. CombatStarted: function(forced)
  1955. {
  1956. if (!window.ET.MCMF.FinishedLoading)
  1957. {
  1958. setTimeout(window.ET.MCMF.CombatStarted, 100);
  1959. return;
  1960. }
  1961.  
  1962. if (forced || (window.ET.MCMF.InternalBattleTickMonitor === undefined) || (window.ET.MCMF.BattleFirstFrame === undefined))
  1963. {
  1964. window.ET.MCMF.InternalBattleTickMonitor = true;
  1965.  
  1966. battleSocket.on('tick', function(oAllData)
  1967. {
  1968. let battleData = window.ET.MCMF.LiveBattleData();
  1969.  
  1970. if (battleData !== undefined)
  1971. {
  1972. /* if (battleData.floor !== undefined)
  1973. {
  1974. let currentFloorRoom = CInt(battleData.floor).toFixed(0) + "." + CInt(battleData.room).toFixed(0);
  1975.  
  1976. if (window.ET.MCMF.BattleFloorRoom !== currentFloorRoom)
  1977. {
  1978. window.ET.MCMF.BattleFloorRoom = currentFloorRoom;
  1979. window.ET.MCMF.BattleFirstFrame = undefined;
  1980. }
  1981. } */
  1982.  
  1983. let CurrentUnitIDList = '';
  1984. jQ.makeArray(battleData.enemies).forEach(function(oEnemyUnit)
  1985. {
  1986. CurrentUnitIDList += `${oEnemyUnit.id}|`;
  1987. });
  1988.  
  1989. let bNewBattleFrameReset = false;
  1990. jQ.makeArray(battleData.enemies).forEach(function(oEnemyUnit)
  1991. {
  1992. if (window.ET.MCMF.LastUnitIDList.indexOf(`${oEnemyUnit.id}|`) === -1)
  1993. bNewBattleFrameReset = true;
  1994. });
  1995.  
  1996. if (bNewBattleFrameReset)
  1997. window.ET.MCMF.BattleFirstFrame = undefined;
  1998.  
  1999. window.ET.MCMF.LastUnitIDList = CurrentUnitIDList;
  2000.  
  2001. if (window.ET.MCMF.BattleFirstFrame === undefined)
  2002. {
  2003. window.ET.MCMF.BattleFirstFrame = battleData;
  2004.  
  2005. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:firstBattleFrame -->");
  2006. window.ET.MCMF.EventTrigger("ET:firstBattleFrame");
  2007.  
  2008. //window.ET.MCMF.Log("new BattleFirstFrame data:");
  2009. //console.log(window.ET.MCMF.BattleFirstFrame);
  2010. }
  2011.  
  2012. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combatTick -->");
  2013. window.ET.MCMF.EventTrigger("ET:combatTick");
  2014. }
  2015. });
  2016. }
  2017. },
  2018.  
  2019. InitGameTriggers: function()
  2020. {
  2021. if ((Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined) || (Template.currentBattleUi === undefined))
  2022. {
  2023. setTimeout(window.ET.MCMF.InitGameTriggers, 100);
  2024. return;
  2025. }
  2026.  
  2027. window.ET.MCMF.EventSubscribe("ET:navigation", function()
  2028. {
  2029. window.ET.MCMF.InternalBattleTickMonitor = undefined;
  2030.  
  2031. // re-trigger combat-start events when the battle socket is reconnected
  2032. if (window.ET.MCMF.InBattle && window.ET.MCMF.IsNewCombatTab())
  2033. window.ET.MCMF.CombatStarted(true);
  2034. });
  2035.  
  2036. Router.onRun(function()
  2037. {
  2038. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:navigation -->");
  2039. window.ET.MCMF.EventTrigger("ET:navigation");
  2040.  
  2041. try
  2042. {
  2043. let sCurrentRoute = Router._currentRoute.getName();
  2044.  
  2045. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(`<-- triggering ET:navigation:${sCurrentRoute} -->`);
  2046. window.ET.MCMF.EventTrigger(`ET:navigation:${sCurrentRoute}`);
  2047. }
  2048. catch (err) { }
  2049.  
  2050. this.next();
  2051. });
  2052.  
  2053. // note: not a trustworthy method to get new battle unit data, since the templates will reuse and not trigger render from room to room
  2054. Blaze._getTemplate("battleUnit").onRendered(function()
  2055. {
  2056. if ((this.data !== undefined) && (this.data.unit !== undefined))
  2057. window.ET.MCMF.BattleUnitList.push(this);
  2058. });
  2059.  
  2060. Template.currentBattleUi.onCreated(function()
  2061. {
  2062. window.ET.MCMF.BattleUITemplate = this;
  2063. });
  2064.  
  2065. Template.currentBattleUi.onDestroyed(function()
  2066. {
  2067. window.ET.MCMF.BattleUITemplate = undefined;
  2068. window.ET.MCMF.BattleUnitList = [];
  2069. });
  2070.  
  2071. Package.meteor.Meteor.connection._stream.on('message', function(sMeteorRawData)
  2072. {
  2073. //if (window.ET.MCMF.CombatID === undefined)
  2074. // window.ET.MCMF.GetPlayerCombatData();
  2075.  
  2076. try
  2077. {
  2078. oMeteorData = JSON.parse(sMeteorRawData);
  2079.  
  2080. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  2081. //
  2082. // BACKUP TO RETRIEVE USER AND COMBAT IDS
  2083. //
  2084. /*
  2085. if (oMeteorData.collection === "users")
  2086. if ((window.ET.MCMF.UserID === undefined) || (window.ET.MCMF.UserID.length !== 17))
  2087. window.ET.MCMF.UserID = oMeteorData.id;
  2088.  
  2089. if (oMeteorData.collection === "combat")
  2090. if ((window.ET.MCMF.CombatID === undefined) || (window.ET.MCMF.CombatID.length !== 17))
  2091. if (oMeteorData.fields.owner === window.ET.MCMF.UserID)
  2092. window.ET.MCMF.CombatID = oMeteorData.id;
  2093. */
  2094. //
  2095. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  2096.  
  2097. if (oMeteorData.collection === "battlesList")
  2098. {
  2099. window.ET.MCMF.AbilitiesReady = false;
  2100.  
  2101. if ((oMeteorData.msg === "added") || (oMeteorData.msg === "removed"))
  2102. {
  2103. window.ET.MCMF.InternalBattleTickMonitor = undefined;
  2104. window.ET.MCMF.BattleFirstFrame = undefined;
  2105. window.ET.MCMF.BattleUnitList = [];
  2106. window.ET.MCMF.InBattle = (oMeteorData.msg === "added");
  2107. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")) + " -->");
  2108. window.ET.MCMF.EventTrigger("ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")));
  2109.  
  2110. if (window.ET.MCMF.InBattle)
  2111. window.ET.MCMF.CombatStarted();
  2112. else
  2113. window.ET.MCMF.BattleFloorRoom = "0.0";
  2114. }
  2115. }
  2116.  
  2117. if ((oMeteorData.collection === "battles") && (oMeteorData.msg === "added"))
  2118. {
  2119. if (oMeteorData.fields.finished)
  2120. {
  2121. window.ET.MCMF.WonLast = oMeteorData.fields.win;
  2122. window.ET.MCMF.TimeLastFight = window.ET.MCMF.Time();
  2123.  
  2124. if (window.ET.MCMF.FinishedLoading)
  2125. {
  2126. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")) + " -->");
  2127. window.ET.MCMF.EventTrigger("ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")));
  2128. }
  2129. }
  2130. else
  2131. window.ET.MCMF.CombatStarted();
  2132. }
  2133. }
  2134. catch (err) { }
  2135. });
  2136. },
  2137.  
  2138. PlayerHP: function()
  2139. {
  2140. return window.ET.MCMF.GetPlayerCombatData().stats.health;
  2141. },
  2142.  
  2143. PlayerHPMax: function()
  2144. {
  2145. return window.ET.MCMF.GetPlayerCombatData().stats.healthMax;
  2146. },
  2147.  
  2148. PlayerEnergy: function()
  2149. {
  2150. return window.ET.MCMF.GetPlayerCombatData().stats.energy;
  2151. },
  2152.  
  2153. AbilityCDCalc: function()
  2154. {
  2155. iTotalCD = 0;
  2156. iTotalCDTest = 0;
  2157. iHighestCD = 0;
  2158.  
  2159. window.ET.MCMF.GetAbilities().forEach(function(oThisAbility)
  2160. {
  2161. if (oThisAbility.equipped)
  2162. {
  2163. if (parseInt(oThisAbility.currentCooldown) > 0)
  2164. {
  2165. iTotalCD += parseInt(oThisAbility.currentCooldown);
  2166. if (iHighestCD < parseInt(oThisAbility.currentCooldown))
  2167. iHighestCD = parseInt(oThisAbility.currentCooldown);
  2168. }
  2169. }
  2170.  
  2171. iTotalCDTest += parseInt(oThisAbility.cooldown);
  2172. });
  2173.  
  2174. if ((iTotalCDTest > 0) && (iTotalCD === 0))
  2175. {
  2176. if (!window.ET.MCMF.AbilitiesReady)
  2177. {
  2178. if (!window.ET.MCMF.InitialAbilityCheck)
  2179. {
  2180. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->");
  2181. window.ET.MCMF.EventTrigger("ET:abilitiesReady");
  2182. }
  2183. }
  2184.  
  2185. window.ET.MCMF.AbilitiesReady = true;
  2186. window.ET.MCMF.TimeLeftOnCD = 0;
  2187. }
  2188. else
  2189. {
  2190. window.ET.MCMF.AbilitiesReady = false;
  2191. window.ET.MCMF.TimeLeftOnCD = iHighestCD;
  2192. }
  2193.  
  2194. window.ET.MCMF.InitialAbilityCheck = false;
  2195. },
  2196.  
  2197. GetUnitCombatData: function(sUnitID)
  2198. {
  2199. let oCombatPlayerData;
  2200.  
  2201. try
  2202. {
  2203. // get recent combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  2204. if (window.ET.MCMF.LiveBattleData() !== undefined)
  2205. {
  2206.  
  2207. jQ.makeArray(window.ET.MCMF.LiveBattleData().units).forEach(function(oCurrentUnit)
  2208. {
  2209. if (oCurrentUnit.id === sUnitID)
  2210. oCombatPlayerData = oCurrentUnit;
  2211. });
  2212. }
  2213. }
  2214. catch (err) { }
  2215.  
  2216. return oCombatPlayerData;
  2217. },
  2218.  
  2219. GetEnemyCombatData: function(sUnitID)
  2220. {
  2221. let oCombatEnemyData;
  2222.  
  2223. try
  2224. {
  2225. // get recent combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  2226. if (window.ET.MCMF.LiveBattleData() !== undefined)
  2227. {
  2228. jQ.makeArray(window.ET.MCMF.LiveBattleData().enemies).forEach(function(oCurrentUnit)
  2229. {
  2230. if (oCurrentUnit.id === sUnitID)
  2231. oCombatEnemyData = oCurrentUnit;
  2232. });
  2233. }
  2234. }
  2235. catch (err) { }
  2236.  
  2237. return oCombatEnemyData;
  2238. },
  2239.  
  2240. GetPlayerCombatData: function()
  2241. {
  2242. try
  2243. {
  2244. Meteor.connection._stores.combat._getCollection().find().fetch().forEach(function(oThisCombatUnit)
  2245. {
  2246. if (oThisCombatUnit.owner === window.ET.MCMF.UserID)
  2247. window.ET.MCMF.PlayerUnitData = oThisCombatUnit;
  2248. });
  2249.  
  2250. // new: get updated combat data from stored 'state' data in 'BattleUITemplate' template (comes from 'battleSocket')
  2251. if (window.ET.MCMF.LiveBattleData() !== undefined)
  2252. {
  2253. jQ.makeArray(window.ET.MCMF.LiveBattleData().units).forEach(function(oCurrentUnit)
  2254. {
  2255. if (oCurrentUnit.id === window.ET.MCMF.UserID)
  2256. window.ET.MCMF.PlayerUnitData = oCurrentUnit;
  2257. });
  2258. }
  2259. }
  2260. catch (err) { }
  2261.  
  2262. return window.ET.MCMF.PlayerUnitData;
  2263. },
  2264.  
  2265. GetAbilities: function()
  2266. {
  2267. return Meteor.connection._stores.abilities._getCollection().find().fetch()[0].learntAbilities;
  2268. },
  2269.  
  2270. GetAdventures: function()
  2271. {
  2272. let oAdventureDetails = { AllAdventures: [], ShortAdventures: [], LongAdventures: [], EpicAdventures: [], PhysicalAdventures: [], MagicalAdventures: [], ActiveAdventures: [], CurrentAdventure: undefined };
  2273.  
  2274. // oThisAdventure
  2275. // .duration {duration in seconds} (integer)
  2276. // .endDate {end date/time} (Date()) (property only exists if the adventure is ongoing)
  2277. // .floor {corresponding Tower Floor} (integer)
  2278. // .icon "{imageofbattle.ext}" (string)
  2279. // .id "{guid}" (13-digit alphanumeric string)
  2280. // .length "short" / "long" / "epic" (string)
  2281. // .level {general level} (integer)
  2282. // .name "{Name of Battle}" (string)
  2283. // .room {corresponding Tower Room in Tower Floor} (integer)
  2284. // .type "physical" / "magic" (string)
  2285. // .startDate {start date/time} (Date()) (property only exists if the adventure is ongoing)
  2286. window.ET.MCMF.GetAdventures_raw().forEach(function(oThisAdventure)
  2287. {
  2288. try
  2289. {
  2290. oAdventureDetails.AllAdventures.push(oThisAdventure);
  2291. if (oThisAdventure.length === "short") oAdventureDetails.ShortAdventures .push(oThisAdventure);
  2292. if (oThisAdventure.length === "long") oAdventureDetails.LongAdventures .push(oThisAdventure);
  2293. if (oThisAdventure.length === "epic") oAdventureDetails.EpicAdventures .push(oThisAdventure);
  2294. if (oThisAdventure.type === "physical") oAdventureDetails.PhysicalAdventures.push(oThisAdventure);
  2295. if (oThisAdventure.type === "magic") oAdventureDetails.MagicalAdventures .push(oThisAdventure);
  2296. if (oThisAdventure.endDate !== undefined) oAdventureDetails.ActiveAdventures .push(oThisAdventure);
  2297. }
  2298. catch (err) { }
  2299. });
  2300.  
  2301. oAdventureDetails.AllAdventures.sort(function(advA, advB)
  2302. {
  2303. if ((advA.startDate === undefined) && (advB.startDate !== undefined)) return 1;
  2304. if ((advA.startDate !== undefined) && (advB.startDate === undefined)) return -1;
  2305. if ((advA.startDate !== undefined) && (advB.startDate !== undefined))
  2306. {
  2307. if (advA.startDate > advB.startDate) return 1;
  2308. if (advA.startDate < advB.startDate) return -1;
  2309. }
  2310. if (advA.duration > advB.duration) return 1;
  2311. if (advA.duration < advB.duration) return -1;
  2312. return 0;
  2313. });
  2314.  
  2315. oAdventureDetails.ActiveAdventures.sort(function(advA, advB)
  2316. {
  2317. if (advA.startDate > advB.startDate) return 1;
  2318. if (advA.startDate < advB.startDate) return -1;
  2319. return 0;
  2320. });
  2321.  
  2322. oAdventureDetails.PhysicalAdventures.sort(function(advA, advB)
  2323. {
  2324. if (advA.duration > advB.duration) return 1;
  2325. if (advA.duration < advB.duration) return -1;
  2326. return 0;
  2327. });
  2328.  
  2329. oAdventureDetails.MagicalAdventures.sort(function(advA, advB)
  2330. {
  2331. if (advA.duration > advB.duration) return 1;
  2332. if (advA.duration < advB.duration) return -1;
  2333. return 0;
  2334. });
  2335.  
  2336. if (oAdventureDetails.ActiveAdventures.length > 0)
  2337. oAdventureDetails.CurrentAdventure = oAdventureDetails.ActiveAdventures[0];
  2338.  
  2339. return oAdventureDetails;
  2340. },
  2341.  
  2342. GetAdventures_raw: function()
  2343. {
  2344. try
  2345. {
  2346. return Meteor.connection._stores.adventures._getCollection().find().fetch()[0].adventures;
  2347. }
  2348. catch (err) { }
  2349.  
  2350. return [];
  2351. },
  2352.  
  2353. GetChats: function()
  2354. {
  2355. return Meteor.connection._stores.simpleChats._getCollection().find().fetch();
  2356. },
  2357.  
  2358. GetItem: function(in__id)
  2359. {
  2360. let oItems = window.ET.MCMF.GetItems({_id: in__id});
  2361.  
  2362. if (oItems.length > 0)
  2363. return oItems[0];
  2364.  
  2365. return {};
  2366. },
  2367.  
  2368. GetItems: function()
  2369. {
  2370. let oItems;
  2371.  
  2372. if (arguments.length === 0)
  2373. oItems = jQ.makeArray(Meteor.connection._stores.items._getCollection().find().fetch());
  2374. else
  2375. oItems = jQ.makeArray(Meteor.connection._stores.items._getCollection().find(arguments[0]).fetch());
  2376.  
  2377. for (let i = 0; i < oItems.length; i++)
  2378. oItems[i] = window.ET.MCMF.AddItemConsts(oItems[i]);
  2379.  
  2380. return oItems;
  2381. },
  2382.  
  2383. AddItemConsts: function(oItem)
  2384. {
  2385. let oItemNew;
  2386. let consts;
  2387.  
  2388. try
  2389. {
  2390. consts = (IsValid(window) && IsValid(window.gameConstants)) ? window.gameConstants : (IsValid(unsafeWindow) && IsValid(unsafeWindow.gameConstants)) ? unsafeWindow.gameConstants : { };
  2391.  
  2392. oItemNew = { ...(oItem) };
  2393. oItemNew = { ...(oItemNew), ...(consts.ITEMS[oItemNew.itemId]) };
  2394.  
  2395. if (IsValid(oItemNew.produces) && IsValid(consts.FARMING) && IsValid(consts.FARMING.plants))
  2396. {
  2397. oItemNew.plantingDetails = consts.FARMING.plants[oItemNew.produces];
  2398.  
  2399. if (IsValid(oItemNew.plantingDetails))
  2400. oItemNew.required = oItemNew.plantingDetails.required;
  2401. }
  2402. }
  2403. catch (err) { }
  2404.  
  2405. try
  2406. {
  2407. oItemNew = { ...(oItemNew), ...(oItem) };
  2408. oItemNew.stats = sumObjectsByKey(oItem.extraStats, consts.ITEMS[oItem.itemId].stats);
  2409. }
  2410. catch (err) { }
  2411.  
  2412. try
  2413. {
  2414. if (typeof oItemNew['description'] === 'function')
  2415. oItemNew.description = oItemNew.description();
  2416. }
  2417. catch (err) { }
  2418.  
  2419. return oItemNew;
  2420. },
  2421.  
  2422. GetItemConsts: function(sItemID)
  2423. {
  2424. let oItemNew;
  2425. let consts;
  2426.  
  2427. try
  2428. {
  2429. consts = (IsValid(window) && IsValid(window.gameConstants)) ? window.gameConstants : (IsValid(unsafeWindow) && IsValid(unsafeWindow.gameConstants)) ? unsafeWindow.gameConstants : { };
  2430.  
  2431. oItemNew = consts.ITEMS[sItemID];
  2432.  
  2433. if (IsValid(oItemNew.produces) && IsValid(consts.FARMING) && IsValid(consts.FARMING.plants))
  2434. {
  2435. oItemNew.plantingDetails = consts.FARMING.plants[oItemNew.produces];
  2436.  
  2437. if (IsValid(oItemNew.plantingDetails))
  2438. oItemNew.required = oItemNew.plantingDetails.required;
  2439. }
  2440. }
  2441. catch (err) { }
  2442.  
  2443. try
  2444. {
  2445. if (typeof oItemNew['description'] === 'function')
  2446. oItemNew.description = oItemNew.description();
  2447. }
  2448. catch (err) { }
  2449.  
  2450. return oItemNew;
  2451. },
  2452.  
  2453. GetSkills: function()
  2454. {
  2455. return Meteor.connection._stores.skills._getCollection().find().fetch();
  2456. },
  2457.  
  2458. Setup: function()
  2459. {
  2460. if ((!window.ET.MCMF.TryingToLoad) && (!window.ET.MCMF.FinishedLoading))
  2461. {
  2462. // use whatever version of jQuery available to us
  2463. $("body").append("<div id=\"ET_meancloud_bootstrap\" style=\"visibility: hidden; display: none;\"></div>");
  2464. window.ET.MCMF.TryingToLoad = true;
  2465. window.ET.MCMF.Setup_Initializer();
  2466. }
  2467. },
  2468.  
  2469. Setup_Initializer: function()
  2470. {
  2471. // wait for Meteor availability
  2472. if ((Package === undefined) || (Package.meteor === undefined) || (Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined))
  2473. {
  2474. setTimeout(window.ET.MCMF.Setup_Initializer, 10);
  2475. return;
  2476. }
  2477.  
  2478. if (!window.ET.MCMF.Initialized)
  2479. {
  2480. window.ET.MCMF.Initialized = true;
  2481. window.ET.MCMF.Setup_SendDelayedInitializer();
  2482. window.ET.MCMF.InitGameTriggers();
  2483. window.ET.MCMF.Setup_remaining();
  2484. }
  2485. },
  2486.  
  2487. Setup_SendDelayedInitializer: function()
  2488. {
  2489. try
  2490. {
  2491. jQ("div#ET_meancloud_bootstrap").trigger("ET:initialized");
  2492. window.ET.MCMF.EventTrigger("ET:initialized");
  2493. }
  2494. catch (err)
  2495. {
  2496. setTimeout(window.ET.MCMF.Setup_SendDelayedInitializer, 100);
  2497. }
  2498. },
  2499.  
  2500. Setup_remaining: function()
  2501. {
  2502. try
  2503. {
  2504. if (Meteor === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  2505. if (Meteor.connection === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  2506. if (Meteor.connection._userId === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized";
  2507.  
  2508. window.ET.MCMF.UserID = Meteor.connection._userId;
  2509. //window.ET.MCMF.UserName = Meteor.connection._stores.users._getCollection()._collection._docs._map[window.ET.MCMF.UserID].username;
  2510. window.ET.MCMF.UserName = [...Meteor.connection._stores.users._getCollection()._collection._docs._map.values()][0].username;
  2511. window.ET.MCMF.GetPlayerCombatData();
  2512.  
  2513. if (window.ET.MCMF.GetAbilities().length < 0) throw "[MCMF Setup] Not loaded yet: no abilities";
  2514. if (window.ET.MCMF.GetItems().length < 0) throw "[MCMF Setup] Not loaded yet: no items";
  2515. if (window.ET.MCMF.GetChats().length < 0) throw "[MCMF Setup] Not loaded yet: no chats";
  2516. if (window.ET.MCMF.GetSkills().length < 0) throw "[MCMF Setup] Not loaded yet: no skills";
  2517.  
  2518. // if the above is all good, then this should be no problem:
  2519.  
  2520. window.ET.MCMF.AbilityCDTrigger(); // set up ability CD trigger
  2521. window.ET.MCMF.AbilityCDCalc();
  2522. window.ET.MCMF.FasterAbilityUpdates(); // set up faster ability updates (do not disable, this is controlled via configurable setting)
  2523.  
  2524. // trigger finished-loading event
  2525. if (!window.ET.MCMF.FinishedLoading)
  2526. {
  2527. if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:loaded -->");
  2528. window.ET.MCMF.EventTrigger("ET:loaded");
  2529. window.ET.MCMF.FinishedLoading = true;
  2530. }
  2531. }
  2532. catch (err) // any errors and we retry setup
  2533. {
  2534. if (err.toString().indexOf("[MCMF Setup]") !== -1)
  2535. {
  2536. window.ET.MCMF.Log("ET MCMF setup exception:");
  2537. console.log(err);
  2538. }
  2539.  
  2540. setTimeout(window.ET.MCMF.Setup_remaining, 500);
  2541. }
  2542. },
  2543.  
  2544. // Ready means the mod framework has been initialized, but Meteor is not yet available
  2545. Ready: function(fnCallback, sNote)
  2546. {
  2547. if (!window.ET.MCMF.Initialized)
  2548. window.ET.MCMF.EventSubscribe("initialized", fnCallback, sNote);
  2549. else
  2550. fnCallback();
  2551. },
  2552.  
  2553. // Loaded means the mod framework and Meteor are fully loaded and available
  2554. Loaded: function(fnCallback, sNote)
  2555. {
  2556. if (!window.ET.MCMF.FinishedLoading)
  2557. window.ET.MCMF.EventSubscribe("loaded", fnCallback, sNote);
  2558. else
  2559. fnCallback();
  2560. },
  2561. };
  2562.  
  2563. window.ET.MCMF.Setup();
  2564. }
  2565. ////////////////////////////////////////////////////////////////
  2566.  
  2567.  
  2568. ////////////////////////////////////////////////////////////////
  2569. ////////// ** CORE SCRIPT STARTUP -- DO NOT MODIFY ** //////////
  2570. function LoadJQ(callback) {
  2571. if (window.jQ === undefined) { var script=document.createElement("script");script.setAttribute("src","//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js");script.addEventListener('load',function() {
  2572. var subscript=document.createElement("script");subscript.textContent="window.jQ=jQuery.noConflict(true);("+callback.toString()+")();";document.body.appendChild(subscript); },
  2573. !1);document.body.appendChild(script); } else callback(); } LoadJQ(startup);
  2574. ////////////////////////////////////////////////////////////////