Adds stats to the UI for the Eternity Tower game
当前为
// ==UserScript== // @name Eternity Tower Stats UI // @icon https://www.eternitytower.net/favicon.png // @namespace http://mean.cloud/ // @version 1.25 // @description Adds stats to the UI for the Eternity Tower game // @match http*://*.eternitytower.net/* // @author [email protected] // @copyright 2017-2018, MeanCloud // @run-at document-end // @grant GM_getValue // @grant GM_setValue // ==/UserScript== //////////////////////////////////////////////////////////////// ////////////// ** SCRIPT GLOBAL INITIALIZATION ** ////////////// function startup() { ET_StatsUIMod(); } ET_Stat_UserID = ""; ET_Stat_CombatID = ""; ET_Stat_CritChance = 0; ET_Stat_CritDamage = 0; ET_Stat_HealingPower = 0; ET_Stat_DamageTaken = 0; ET_Stat_MP = 0; ET_JustExpanded = false; ET_LastModal = null; ET_LastForm = null; //////////////////////////////////////////////////////////////// ET_StatsUIMod = function() { ET.MCMF.Ready(function() { //ET.MCMF.WantDebug = true; Meteor.connection._stream.on('message', function(sMeteorRawData) { try { var oMeteorData = JSON.parse(sMeteorRawData); if (oMeteorData.collection == "users") { //console.log(oMeteorData); ET_Stat_UserID = oMeteorData.id; } if (oMeteorData.collection == "combat") if ((oMeteorData.fields.owner === ET_Stat_UserID) &&( ET_Stat_CombatID === "")) ET_Stat_CombatID = oMeteorData.id; if (oMeteorData.collection == "combat") { if ((oMeteorData.fields.owner === ET_Stat_UserID) || (oMeteorData.id === ET_Stat_CombatID)) { //console.log(oMeteorData); ET_Stat_CritChance = oMeteorData.fields.stats.criticalChance; ET_Stat_CritDamage = oMeteorData.fields.stats.criticalDamage; ET_Stat_HealingPower = oMeteorData.fields.stats.healingPower; ET_Stat_DamageTaken = oMeteorData.fields.stats.damageTaken; ET_Stat_MP = oMeteorData.fields.stats.magicPower; /* var oHPEl = jQ("div.bg-danger").parent().parent().find("div.d-flex > i.extra-small-icon").parent(); if (jQ("#PET_DemonMaxHP").length === 0) oHPEl.append("<span id=\"PET_DemonMaxHP\" style=\"white-space: nowrap; font-size: 9pt;\"></span>"); jQ("#PET_DemonMaxHP").html(" (demon < " + ((oMeteorData.fields.stats.healthMax * 0.2) + 1).toFixed(0) + ")"); */ } } } catch (err) { } }); }); ET.MCMF.Loaded(function() { ET.MCMF.StatsUIMod = { }; ET.MCMF.StatsUIMod.WantAdventureLoot = (GM_getValue("PETStatusUI_WantAdventureLoot") !== false); // default true //GM_setValue("PETSearch_Color", jQ("#PETSItemColor") .is(":checked")); // Set background tasks ET_StatsUIMod_DPSShow(); }); }; ET_StatsUIMod_GetAdventure = function(sMatchID) { // oAdventure // .duration // .endDate // .floor // .icon // .id // .length // .level // .name // .room // .type // .startDate var oAdventureData; jQuery.makeArray(Object.keys(Package.meteor.global.Accounts.connection._stores.adventures._getCollection()._collection._docs._map).map(key => Package.meteor.global.Accounts.connection._stores.adventures._getCollection()._collection._docs._map[key])[0].adventures).forEach(function(oAdventure) { try { if (oAdventure.id === sMatchID) oAdventureData = oAdventure; } catch (err) { } }); return oAdventureData; }; var sETStatsDB = ""; var ETStatsDB_PQ = []; var ETStatsDB_Tower = []; ET_StatsUIMod_ConvertItemIDToImage = function(sItemID) { var s = sItemID; var sExt = ".svg"; if (endsWith(s, "_essence")) sExt = ".png"; if (endsWith(s, "_shield")) sExt = ".png"; if (endsWith(s, "_scimitar")) sExt = ".png"; if (endsWith(s, "_broad_sword")) sExt = ".png"; if (endsWith(s, "_plate") && (s !== "opal_chest_plate")) sExt = ".png"; if (s.indexOf("_wizard") !== -1) sExt = ".png"; if (endsWith(s, "_battle_axe")) sExt = ".png"; if (endsWith(s, "_long_sword")) sExt = ".png"; if (endsWith(s, "_helm")) sExt = ".png"; if (endsWith(s, "_knife")) sExt = ".png"; if (endsWith(s, "_wand")) sExt = ".png"; if (endsWith(s, "_spear")) sExt = ".png"; if (endsWith(s, "_rapiers")) sExt = ".png"; if (endsWith(s, "_dagger")) sExt = ".png"; if (endsWith(s, "_log")) sExt = ".png"; if (startsWith(s, "ore_")) { s = s.substr(4); sExt = ".png"; } if (startsWith(s, "poison_shard")) sExt = ".png"; if (startsWith(s, "fire_shard")) sExt = ".png"; if (startsWith(s, "earth_shard")) sExt = ".png"; if (startsWith(s, "air_shard")) sExt = ".png"; if (startsWith(s, "water_shard")) sExt = ".png"; if (s.indexOf("_tome") !== -1) s = "tome"; while (s.indexOf("_a") !== -1) s = s.replace("_a", "A"); while (s.indexOf("_b") !== -1) s = s.replace("_b", "B"); while (s.indexOf("_c") !== -1) s = s.replace("_c", "C"); while (s.indexOf("_d") !== -1) s = s.replace("_d", "D"); while (s.indexOf("_e") !== -1) s = s.replace("_e", "E"); while (s.indexOf("_f") !== -1) s = s.replace("_f", "F"); while (s.indexOf("_g") !== -1) s = s.replace("_g", "G"); while (s.indexOf("_h") !== -1) s = s.replace("_h", "H"); while (s.indexOf("_i") !== -1) s = s.replace("_i", "I"); while (s.indexOf("_j") !== -1) s = s.replace("_j", "J"); while (s.indexOf("_k") !== -1) s = s.replace("_k", "K"); while (s.indexOf("_l") !== -1) s = s.replace("_l", "L"); while (s.indexOf("_m") !== -1) s = s.replace("_m", "M"); while (s.indexOf("_n") !== -1) s = s.replace("_n", "N"); while (s.indexOf("_o") !== -1) s = s.replace("_o", "O"); while (s.indexOf("_p") !== -1) s = s.replace("_p", "P"); while (s.indexOf("_q") !== -1) s = s.replace("_q", "Q"); while (s.indexOf("_r") !== -1) s = s.replace("_r", "R"); while (s.indexOf("_s") !== -1) s = s.replace("_s", "S"); while (s.indexOf("_t") !== -1) s = s.replace("_t", "T"); while (s.indexOf("_u") !== -1) s = s.replace("_u", "U"); while (s.indexOf("_v") !== -1) s = s.replace("_v", "V"); while (s.indexOf("_w") !== -1) s = s.replace("_w", "W"); while (s.indexOf("_x") !== -1) s = s.replace("_x", "X"); while (s.indexOf("_y") !== -1) s = s.replace("_y", "Y"); while (s.indexOf("_z") !== -1) s = s.replace("_z", "Z"); s = s.split('_').join(''); s = s + sExt; return s; }; ET_StatsUIMod_GetDropsForTower = function(iFloor, iRoom) { var sResults = ""; try { if (ETStatsDB_Tower[iFloor][iRoom] !== undefined) { jQuery.makeArray(ETStatsDB_Tower[iFloor][iRoom]).forEach(function(dropInfo) { try { //if (sResults !== "") sResults += ", "; //sResults += dropInfo.name + " (" + dropInfo.percent.toString() + "%)"; var s = ET_StatsUIMod_ConvertItemIDToImage(dropInfo.name); var sHover = dropInfo.name + " (" + dropInfo.percent.toString() + "%)"; //sResults += "<img src=\"/icons/" + s + "\" class=\"ml-1 extra-small-icon\" />"; sResults += "<img src=\"/icons/" + s + "\" style=\"width: 24px; height: 24px; font-size: 24px; line-height: 24px;\" alt=\"" + sHover + "\" title=\"" + sHover + "\">"; } catch (err) { } }); } } catch (err) { } return sResults; }; ET_StatsUIMod_LoadETStatsDatabase = function() { if (sETStatsDB !== "") return; try { sETStatsDB = "busy"; jQ.get("https://news.mediacentermaster.com/ETStats/", function(data) { try { // don't hold bad data if (data.indexOf("Level 50-54") === -1) { sETStatsDB = ""; return; } sETStatsDB = data; ETStatsDB_PQ = []; ETStatsDB_Tower = []; //console.log("ET Stats loaded!"); //console.log(sETStatsDB); let rawPQData = ChopperBlank(sETStatsDB, "<pre>", "Tower").trim().split("Level "); //ETStatsDB_Tower jQuery.makeArray(rawPQData).forEach(function(rawPQChunk) { //console.log("Raw PQ chunk: " + rawPQChunk.trim()); let iRangeStart = 0; let iRangeEnd = 0; jQuery.makeArray(rawPQChunk.trim().split("\n")).forEach(function(rawPQLine, idx, arr) { try { rawPQLine = rawPQLine.trim(); //console.log(idx.toString() + " :: " + rawPQLine); if (idx === 0) { iRangeStart = CInt(ChopperBlank(rawPQLine, "", "-")); iRangeEnd = CInt(ChopperBlank(rawPQLine, "-", " ")); } else if ((iRangeStart > 0) && (iRangeEnd > 0)) { let temp_Percent = CDbl(ChopperBlank(rawPQLine, "", "%")); let temp_Name = ChopperBlank(rawPQLine, " - ", " (").trim(); let oDataObj = { name: temp_Name, percent: temp_Percent }; for (let i = iRangeStart; i <= iRangeEnd; i++) { if (ETStatsDB_PQ[i] === undefined) ETStatsDB_PQ[i] = []; ETStatsDB_PQ[i].push(oDataObj); } //console.log("PQ data recorded: L" + iRangeStart.toString() + "-L" + iRangeEnd.toString() + " " + JSON.stringify(oDataObj)); } } catch (err) { console.log("PQ line parse failure: " + JSON.stringify(err)); } }); }); let rawTowerData = ChopperBlank(sETStatsDB, "Tower F0R0", "</pre>").trim().split("Tower "); //ETStatsDB_Tower jQuery.makeArray(rawTowerData).forEach(function(rawTowerChunk) { let iFloor = CInt(ChopperBlank(rawTowerChunk, "F", "R")); let iRoom = CInt(ChopperBlank(rawTowerChunk, "R", " - ")); // don't hold data for full tower floor runs or any invalid data if ((iFloor === 0) || (iRoom === 0)) return; jQuery.makeArray(rawTowerChunk.trim().split("\n")).forEach(function(rawTowerLine, idx, arr) { try { rawTowerLine = rawTowerLine.trim(); //console.log(idx.toString() + " :: " + rawTowerLine); if (idx === 0) return; let temp_Percent = CDbl(ChopperBlank(rawTowerLine, "", "%")); let temp_Name = ChopperBlank(rawTowerLine, " - ", " (").trim(); let oDataObj = { name: temp_Name, percent: temp_Percent }; if (ETStatsDB_Tower[iFloor] === undefined) ETStatsDB_Tower[iFloor] = []; if (ETStatsDB_Tower[iFloor][iRoom] === undefined) ETStatsDB_Tower[iFloor][iRoom] = []; ETStatsDB_Tower[iFloor][iRoom].push(oDataObj); //console.log("Tower data recorded: F" + iFloor.toString() + "R" + iRoom.toString() + " " + JSON.stringify(oDataObj)); } catch (err) { console.log("Tower line parse failure: " + JSON.stringify(err)); } }); }); let i; for (i = 0; i <= 1000; i++) { if (ETStatsDB_PQ[i] !== undefined) { //console.log("PQ L" + i.toString() + " sorted!"); ETStatsDB_PQ[i].sort(function(dropInfo_a, dropInfo_b) { if (dropInfo_a.percent > dropInfo_b.percent) return -1; if (dropInfo_a.percent < dropInfo_b.percent) return 1; return 0; }); } } for (i = 0; i <= 30; i++) { if (ETStatsDB_Tower[i] !== undefined) { for (let j = 0; j <= 30; j++) { if (ETStatsDB_Tower[i][j] !== undefined) { //console.log("Tower F" + i.toString() + "R" + j.toString() + " sorted!"); ETStatsDB_Tower[i][j].sort(function(dropInfo_a, dropInfo_b) { if (dropInfo_a.percent > dropInfo_b.percent) return -1; if (dropInfo_a.percent < dropInfo_b.percent) return 1; return 0; }); } } } } } catch (err) { sETStatsDB = ""; } }); } catch (err) { } }; ET_StatsUIMod_DPSShow = function() { var i = 0; var oStatLines = null; var sBareDamageRange = ""; var sBareAttackSpeed = ""; var sBareCriticalChance = ""; var dDamageMin = 0.0; var dDamageMax = 0.0; var sDamagePartMin = ""; var sDamagePartMax = ""; var dAverageDamageAvgQuality = 0.0; var dAverageDamageMaxQuality = 0.0; var sThisLine = ""; var sThisLineText = ""; var dAttackSpeed = 0.0; var dActualDPSAverageQuality = 0.0; var dActualDPSMaxQuality = 0.0; var dCriticalChance = 0.0; /////////////////////////////////////////////////////////////////////////////////////// // // Adventure Details // ET_StatsUIMod_LoadETStatsDatabase(); // loads on demand try { // Options if ((ET.MCMF.GetActiveTab() === "combat") /* && (ET.MCMF.GetActiveTabSection() === "adventures") */) { if (jQ("div.PETStatusUI_Menu").length === 0) { var oTemp = jQ(jQ("body div.body-content div div div div[style=\"margin-bottom: 5px;\"]").get(0)); if (oTemp.text().trim() == "Buy adventure"); // sanity check { oTemp = oTemp.parent(); oTemp.before("<div class=\"PETStatusUI_Menu d-flex flex-row flex-wrap\"></div>"); oTemp.appendTo("div.PETStatusUI_Menu"); oTemp = jQ("div.PETStatusUI_Menu"); oTemp.prepend ( "<div>" + "<div style=\"margin-bottom: 5px;\">Options</div>" + "<button class=\"buy-new-adventure btn btn-secondary PETStatusUI_btnShowHideLoot\">Loot: " + ((ET.MCMF.StatsUIMod.WantAdventureLoot) ? "Shown" : "Hidden") + "</button>" + "</div>" ); oTemp.children("div").addClass("d-flex flex-column my-1 mx-1"); oTemp.find("button").css("height", "40px").css("max-height", "40px").css("line-height", "24px"); // normalize the button heights jQ(".PETStatusUI_btnShowHideLoot").click(function() { ET.MCMF.StatsUIMod.WantAdventureLoot = !ET.MCMF.StatsUIMod.WantAdventureLoot; GM_setValue("PETStatusUI_WantAdventureLoot", ET.MCMF.StatsUIMod.WantAdventureLoot); jQ(".PETStatusUI_btnShowHideLoot").text((ET.MCMF.StatsUIMod.WantAdventureLoot) ? "Loot: Shown" : "Loot: Hidden"); }); } } // Adventure loot lines if (ET.MCMF.StatsUIMod.WantAdventureLoot) { jQ("div.PETSDetails_error").remove(); jQ("div.adventure-item-container").each(function() { try { var sAdvID = jQ(this).find("button").attr("data-id"); var oAdventureData = ET_StatsUIMod_GetAdventure(sAdvID); if (jQ(this).find("div.PETSDetails_success").length > 0) return; jQ(this).find("div.PETSDetails").remove(); var sLoot = ET_StatsUIMod_GetDropsForTower(oAdventureData.floor, oAdventureData.room); if (sLoot !== "") { jQ(this).append("<div class=\"d-flex PETSDetails PETSDetails_success\"><div class=\"d-flex\" style=\"margin-left: 60px;\">" + sLoot + "</div></div>\r\n"); } else { jQ(jQ(this).find("div.ml-3").get(0)).append("<div class=\"PETSDetails PETSDetails_error\">Loot From F" + oAdventureData.floor.toString() + "R" + oAdventureData.room.toString() + "</div>\r\n"); 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"); } } catch (err) { } }); } else jQ(".PETSDetails").remove(); } else { jQ("div.PETStatusUI_Menu").remove(); } } catch (err) { ET.MCMF.Log(err); } // /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // // Stat Descriptions // jQ(".PeteUI_TooltipStat").remove(); // Removed: this is baked into the actual game now /* jQ("div.item-tooltip-content div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\"> attacks per second</span>"); jQ("div.item-tooltip-content div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\"> accuracy</span>"); jQ("div.item-tooltip-content div i.lilIcon-criticalChance").parent().append("<span class=\"PeteUI_TooltipStat\"> crit. chance</span>"); jQ("div.item-tooltip-content div i.lilIcon-healthMax").parent().append("<span class=\"PeteUI_TooltipStat\"> max. health</span>"); jQ("div.item-tooltip-content div i.lilIcon-defense").parent().append("<span class=\"PeteUI_TooltipStat\"> dodge (defense)</span>"); jQ("div.item-tooltip-content div i.lilIcon-armor").parent().append("<span class=\"PeteUI_TooltipStat\"> physical armor</span>"); jQ("div.item-tooltip-content div i.lilIcon-magicPower").parent().append("<span class=\"PeteUI_TooltipStat\"> magic power</span>"); jQ("div.item-tooltip-content div i.lilIcon-magicArmor").parent().append("<span class=\"PeteUI_TooltipStat\"> magic armor</span>"); jQ("div.item-tooltip-content div i.lilIcon-healingPower").parent().append("<span class=\"PeteUI_TooltipStat\"> increased healing %</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\"> attacks per second</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\"> accuracy</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-criticalChance").parent().append("<span class=\"PeteUI_TooltipStat\"> crit. chance</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-healthMax").parent().append("<span class=\"PeteUI_TooltipStat\"> max. health</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-defense").parent().append("<span class=\"PeteUI_TooltipStat\"> dodge (defense)</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-armor").parent().append("<span class=\"PeteUI_TooltipStat\"> physical armor</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-magicPower").parent().append("<span class=\"PeteUI_TooltipStat\"> magic power</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-magicArmor").parent().append("<span class=\"PeteUI_TooltipStat\"> magic armor</span>"); jQ("form.craft-amount-form div.modal-body > div i.lilIcon-healingPower").parent().append("<span class=\"PeteUI_TooltipStat\"> increased healing %</span>"); */ // /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // // Woodcutters // jQ("div.item-tooltip-content").each(function() { try { if (jQ(this).find("div.PeteUI_TooltipStatWC").length === 0) { if (jQ(this).html().toLowerCase().indexOf("lumber jack") !== -1) { jQ(this).find("div i.lilIcon-attack").parent().append("<span class=\"PeteUI_TooltipStat\"> wood cut tier</span>"); jQ(this).find("div i.lilIcon-attackSpeed").parent().append("<span class=\"PeteUI_TooltipStat\"> attacks per second</span>"); jQ(this).find("div i.lilIcon-accuracy").parent().append("<span class=\"PeteUI_TooltipStat\"> accuracy</span>"); } } } catch (err) { } }); // /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // // Crafting Recipes // try { if (jQ("a.show-stats").length > 0) { ET_LastForm = jQ("a.show-stats").parent().parent(); ET_LastModal = ET_LastForm.parent().parent().parent(); jQ("a.show-stats")[0].click(); // auto-expand base stats for crafting ranges (needed anyway to calculate extra stats) ET_JustExpanded = true; } if ((ET_LastModal !== null) && (ET_LastModal.hasClass("show")) && (ET_JustExpanded === true)) { var oForm = ET_LastForm; //oForm = jQ("form.craft-amount-form"); if (oForm.html().indexOf("Hide Stat Range") !== -1) { oStatLines = oForm.find("div.modal-body > div"); for (i = 1; i < oStatLines.length; i++) { sThisLine = jQ(oStatLines.get(i)).html().trim(); sThisLineText = jQ(oStatLines.get(i)).text().trim(); if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") === -1)) continue; if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sBareDamageRange === "")) sBareDamageRange = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-attackSpeed ") !== -1) sBareAttackSpeed = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-criticalChance ") !== -1) sBareCriticalChance = sThisLineText + " [[#" + i.toString() + "]]"; } //console.log("******************BEGIN******************"); //console.log("Bare DPS: " + sBareDamageRange); //console.log("Bare attack speed: " + sBareAttackSpeed); //console.log("Bare crit chance: " + sBareCriticalChance); //console.log("*******************END*******************"); sBareDamageRange = ChopperBlank(sBareDamageRange.replace(' attack', '').replace(' damage', '') + "\n", "", "\n").trim(); sBareAttackSpeed = ChopperBlank(sBareAttackSpeed.replace(' attack speed', '') + "\n", "", "\n").trim(); sBareCriticalChance = ChopperBlank(sBareCriticalChance.replace(' critical chance', '') + "\n", "", "\n").trim(); //console.log("******************BEGIN******************"); //console.log("Bare DPS: " + sBareDamageRange); //console.log("Bare attack speed: " + sBareAttackSpeed); //console.log("Bare crit chance: " + sBareCriticalChance); //console.log("*******************END*******************"); if (sBareDamageRange.indexOf("(") !== -1) { sDamagePartMin = ChopperBlank(sBareDamageRange, "", ") - (") + ")"; sDamagePartMax = "(" + ChopperBlank(sBareDamageRange, ") - (", ""); var dDamageRangeLow1 = CDbl(ChopperBlank(sDamagePartMin, "(", " - ").trim()); var dDamageRangeLow2 = CDbl(ChopperBlank(sDamagePartMin, " - ", ")").trim()); dDamageMin = (dDamageRangeLow1 + dDamageRangeLow2) / 2.0; var dDamageRangeHigh1 = CDbl(ChopperBlank(sDamagePartMax, "(", " - ").trim()); var dDamageRangeHigh2 = CDbl(ChopperBlank(sDamagePartMax, " - ", ")").trim()); dDamageMax = (dDamageRangeHigh1 + dDamageRangeHigh2) / 2.0; dAverageDamageMaxQuality = ((dDamageRangeHigh2 - dDamageRangeLow2) / 2.0) + dDamageRangeLow2; } else { sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - "); sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", ""); dDamageMin = CDbl(sDamagePartMin); dDamageMax = CDbl(sDamagePartMax); dAverageDamageMaxQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin; } dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin; dAttackSpeed = CDbl(sBareAttackSpeed); dCriticalChance = CDbl(sBareCriticalChance); if (dCriticalChance > 0.0) { dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); dAverageDamageMaxQuality += dAverageDamageMaxQuality * (dCriticalChance / 100.0); } dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed; dActualDPSMaxQuality = dAverageDamageMaxQuality * dAttackSpeed; if (!isNaN(dActualDPSAverageQuality)) { oForm.find("div.modal-body").append ( "<div class=\"d-flex flex-wrap\"></div><b>Rated Damage at 50% Quality</b>\r\n" + "<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" + "<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" + "<b>Rated Damage at 100% Quality</b>\r\n" + "<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" + "<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" ); } ET_JustExpanded = false; } } } catch (err) { console.log("ERROR: " + err); } // /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // // Item Hover Tooltips (Combat > Equipment & Stats, Wodcutting, viewing profiles, etc.) // try { jQ("div.item-tooltip-content").each(function() { if (jQ(this).find("div.PeteUI_TooltipExp").length !== 0) return; sBareDamageRange = ""; sBareAttackSpeed = ""; sBareAccuracy = ""; sBareCriticalChance = ""; sBareEnergyPerHit = ""; sBareEnergyRegen = ""; var bIsWoodcutter = false; oStatLines = jQ(this).find("div > div"); for (i = 0; i < oStatLines.length; i++) { sThisLine = jQ(oStatLines.get(i)).html().trim(); sThisLineText = jQ(oStatLines.get(i)).text().trim(); //console.log("DEBUG::" + sThisLine); //console.log("DEBUG::" + sThisLineText); if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") !== -1) && (sBareDamageRange === "")) sBareDamageRange = sThisLineText + " [[#" + i.toString() + "]]"; 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() + "]]"; } else if ((sThisLine.indexOf("lilIcon-attack ") !== -1) && (sThisLine.indexOf(" - ") === -1) && (sBareDamageRange === "")) { bIsWoodcutter = true; sBareDamageRange = sThisLineText + " - " + sThisLineText + " [[#" + i.toString() + "]]"; } else if (sThisLine.indexOf("lilIcon-attackSpeed ") !== -1) sBareAttackSpeed = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-accuracy ") !== -1) sBareAccuracy = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-criticalChance ") !== -1) sBareCriticalChance = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-energyPerHit ") !== -1) sBareEnergyPerHit = sThisLineText + " [[#" + i.toString() + "]]"; else if (sThisLine.indexOf("lilIcon-energyRegen ") !== -1) sBareEnergyRegen = sThisLineText + " [[#" + i.toString() + "]]"; } //console.log("******************BEGIN******************"); //console.log("Bare DPS: " + sBareDamageRange); //console.log("Bare attack speed: " + sBareAttackSpeed); //console.log("Bare accuracy: " + sBareAccuracy); //console.log("Bare crit chance: " + sBareCriticalChance); //console.log("Bare energy per hit: " + sBareEnergyPerHit); //console.log("Bare energy regen: " + sBareEnergyRegen); //console.log("*******************END*******************"); sBareDamageRange = ChopperBlank(sBareDamageRange.replace(' damage', '').replace(' damage', '') + "\n", "", "\n").trim(); sBareAttackSpeed = ChopperBlank(sBareAttackSpeed.replace(' attack speed', '') + "\n", "", "\n").trim(); sBareAccuracy = ChopperBlank(sBareAccuracy.replace(' accuracy', '').trim() + " ", "", " ").trim(); sBareCriticalChance = ChopperBlank(sBareCriticalChance.replace(' critical chance', '') + "\n", "", "\n").trim(); sBareEnergyPerHit = ChopperBlank(sBareEnergyPerHit.replace(' energy per hit', '') + "\n", "", "\n").trim(); sBareEnergyRegen = ChopperBlank(sBareEnergyRegen.replace(' energy regen', '') + "\n", "", "\n").trim(); //console.log("******************BEGIN******************"); //console.log("Bare DPS: " + sBareDamageRange); //console.log("Bare attack speed: " + sBareAttackSpeed); //console.log("Bare accuracy: " + sBareAccuracy); //console.log("Bare crit chance: " + sBareCriticalChance); //console.log("Bare energy per hit: " + sBareEnergyPerHit); //console.log("Bare energy regen: " + sBareEnergyRegen); //console.log("*******************END*******************"); sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - "); sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", ""); dDamageMin = CDbl(sDamagePartMin); dDamageMax = CDbl(sDamagePartMax); dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin; dAttackSpeed = CDbl(sBareAttackSpeed); dCriticalChance = CDbl(sBareCriticalChance); if (dCriticalChance > 0.0) dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed; if (!isNaN(dActualDPSAverageQuality) && !bIsWoodcutter) { if (jQ(this).find("div.PeteUI_TooltipExp").length === 0) { jQ(jQ(this).find("div").get(0)).append ( "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><b>Rated Damage</b>\r\n" + "<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" + "<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" ); } } else if (CDbl(sBareEnergyPerHit) > 0.0) { if (jQ(this).find("div.PeteUI_TooltipExp").length === 0) { dActualDPSAverageQuality = dAverageDamageAvgQuality / CDbl(sBareEnergyPerHit) * CDbl(sBareEnergyRegen); jQ(jQ(this).find("div").get(0)).append ( "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><b>Rated Efficiency</b>\r\n" + "<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" ); } } else if ((dAttackSpeed > 0.0) && (CDbl(sBareAccuracy) > 0.0) && (bIsWoodcutter)) { if (jQ(this).find("div.PeteUI_TooltipExp").length === 0) { dActualDPSAverageQuality = CDbl(sBareAccuracy) * dAttackSpeed; var sTier = "maple logs (only)"; if (CInt(dAverageDamageAvgQuality) === 5) sTier = "beech logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 10) sTier = "ash logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 15) sTier = "oak logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 20) sTier = "maple logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 25) sTier = "walnut logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 30) sTier = "cherry logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 35) sTier = "mahogany logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 40) sTier = "elm logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 45) sTier = "black logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 50) sTier = "blue gum logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 55) sTier = "cedar logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 60) sTier = "denya logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 65) sTier = "gombe logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 70) sTier = "hickory logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 75) sTier = "larch logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 80) sTier = "poplar logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 85) sTier = "tali logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 90) sTier = "willow logs (and lower)"; else if (CInt(dAverageDamageAvgQuality) === 95) sTier = "teak logs (and lower)"; jQ(jQ(this).find("div").get(0)).append ( "<div class=\"PeteUI_TooltipExp\"><div class=\"d-flex flex-wrap\"></div><br /><b>Rated Efficiency</b>\r\n" + "<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" + "<div class=\"d-flex flex\" style=\"white-space: nowrap;\"><b class=\"lilIcon-woodcutter extra-small-icon mx-1\"></b> chops " + sTier + "</div>\r\n" ); } } }); } catch (err) { console.log("ERROR: " + err); } // /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // // Combat Stats page (personal) // try { if (ET.MCMF.GetActiveTab() == "combat") { if (ET.MCMF.IsNewCombatTab()) { if (jQ("div.lobby-container").find("div.mb-1").html().toLowerCase().indexOf("combat levels") !== -1) { var oCombatData = ET.MCMF.GetPlayerCombatData(); jQ(".PeteUI_CombatStat").remove(); dDamageMin = oCombatData.stats.attack; dDamageMax = oCombatData.stats.attackMax; dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin; dAttackSpeed = oCombatData.stats.attackSpeed; dCriticalChance = oCombatData.stats.criticalChance; if (dCriticalChance > 0.0) dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); // note: not using ET_Stat_CritDamage! dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed; //jQ("a.recent-battles-btn").parent().parent().before( jQ("div.lobby-container").append( "<div class=\"PeteUI_CombatStat\">\r\n" + " <div class=\"mb-1 text-muted\">Combat Stats</div>\r\n" + " <div class=\"d-flex\">" + " <div class=\"col\">" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-attack small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Weapon Damage</div>\r\n" + " <small class=\"mx-3\">" + dDamageMin.toFixed(1) + " - " + dDamageMax.toFixed(1) + " (" + dAverageDamageAvgQuality.toFixed(1) + " average)</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-accuracy small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Accuracy</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.accuracy.toFixed(1) + "</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-defense small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Defense (Dodge)</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.defense.toFixed(1) + "</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-health small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Health (Max)</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.healthMax.toFixed(0) + "</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-magicPower small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Magic Power</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.magicPower.toFixed(1) + "</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/airDart.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Air Dart</div>\r\n" + " <small class=\"mx-3\">" + ((1.10 * oCombatData.stats.magicPower) + 1).toFixed(0) + " armor reduction</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/lightningDart.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Lightning Dart</div>\r\n" + " <small class=\"mx-3\">" + ((0.90 * oCombatData.stats.magicPower) + 2).toFixed(0) + " armor reduction</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"col\">\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-attackSpeed small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Attack Speed</div>\r\n" + " <small class=\"mx-3\">" + dAttackSpeed.toFixed(1) + " attacks per second (" + dActualDPSAverageQuality.toFixed(1) + " DPS)</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-criticalChance small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Critical Hit</div>\r\n" + " <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" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-armor small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Physical Armor</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.armor.toFixed(1) + " (" + ((1000-(100/(100+oCombatData.stats.armor)*1000))/10).toFixed(1) + "% physical protection)</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-noimage small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\"></div>\r\n" + " <small class=\"mx-3\"></small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-magicArmor small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Magic Armor</div>\r\n" + " <small class=\"mx-3\">" + oCombatData.stats.magicArmor.toFixed(1) + " (" + ((1000-(100/(100+oCombatData.stats.magicArmor)*1000))/10).toFixed(1) + "% magic protection)</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-noimage small-icon\"><img src=\"/icons/airBall.svg\" class=\"extra-small-icon\" style=\"margin-top: -16px;\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Air Ball</div>\r\n" + " <small class=\"mx-3\">" + ((1.60 * oCombatData.stats.magicPower) + 10).toFixed(0) + " armor reduction</small>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " <div class=\"d-flex flex-wrap\">\r\n" + " <div class=\"mb-3 mr-3\">\r\n" + " <div class=\"d-flex align-items-center\">\r\n" + " <i class=\"lilIcon-healingPower small-icon\"></i>\r\n" + " <div class=\"ml-1 mb-0\">Healing Power</div>\r\n" + " <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" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + " </div>\r\n" + "</div>\r\n"); } } else if ((!ET.MCMF.IsNewCombatTab()) && (jQ("div.stats-row").length > 0)) { sBareDamageRange = CondenseSpacing(jQ(jQ("div.stats-row").find("div > div.col > div").get(0)).text().trim().replaceAll('\r', ' ').replaceAll('\n', ' ')); //console.log("Bare damage range: " + sBareDamageRange); sDamagePartMin = ChopperBlank(sBareDamageRange, "", " - "); sDamagePartMax = ChopperBlank(sBareDamageRange, " - ", ""); dDamageMin = CDbl(sDamagePartMin); dDamageMax = CDbl(sDamagePartMax); dAverageDamageAvgQuality = ((dDamageMax - dDamageMin) / 2.0) + dDamageMin; sBareAttackSpeed = jQ(jQ("div.stats-row").find("div > div.col > div").get(1)).text().trim(); //console.log("Bare attack speed: " + sBareAttackSpeed); dAttackSpeed = CDbl(sBareAttackSpeed); dCriticalChance = CDbl(ET_Stat_CritChance); if (dCriticalChance > 0.0) dAverageDamageAvgQuality += dAverageDamageAvgQuality * (dCriticalChance / 100.0); // note: not using ET_Stat_CritDamage! dActualDPSAverageQuality = dAverageDamageAvgQuality * dAttackSpeed; //console.log(dActualDPSAverageQuality.toFixed(1)); if (!isNaN(dActualDPSAverageQuality)) { jQ(".PeteUI_CombatStat").remove(); jQ(jQ("div.stats-row").find("div > div.col > div").get(0)).append("<span class=\"PeteUI_CombatStat\"> (" + dAverageDamageAvgQuality.toFixed(1) + " average)</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(1)).append("<span class=\"PeteUI_CombatStat\"> attacks per second (" + dActualDPSAverageQuality.toFixed(1) + " DPS)</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(2)).append("<span class=\"PeteUI_CombatStat\"> magic power</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(3)).append("<span class=\"PeteUI_CombatStat\"> accuracy</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(4)).append("<span class=\"PeteUI_CombatStat\"> health</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(5)).append("<span class=\"PeteUI_CombatStat\"> dodge (defense)</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(6)).append("<span class=\"PeteUI_CombatStat\"> physical armor</span>"); jQ(jQ("div.stats-row").find("div > div.col > div").get(7)).append("<span class=\"PeteUI_CombatStat\"> magic armor</span>"); if (CDbl(ET_Stat_CritChance) > 0.0) 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"); else 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"); if (CDbl(ET_Stat_HealingPower) !== 0.0) 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"); else 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"); //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"); //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"); 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"); 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"); 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"); 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"); 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"); } } } } catch (err) { console.log("ERROR: " + err); } // /////////////////////////////////////////////////////////////////////////////////////// setTimeout(ET_StatsUIMod_DPSShow, 1000); }; //////////////////////////////////////////////////////////////// /////////////// ** common.js -- DO NOT MODIFY ** /////////////// time_val = function() { return CDbl(Math.floor(Date.now() / 1000)); }; IsValid = function(oObject) { if (oObject === undefined) return false; if (oObject === null) return false; return true; }; Random = function(iMin, iMax) { return parseInt(iMin + Math.floor(Math.random() * iMax)); }; ShiftClick = function(oEl) { jQ(oEl).trigger(ShiftClickEvent()); }; ShiftClickEvent = function(target) { let shiftclickOrig = jQ.Event("click"); shiftclickOrig.which = 1; // 1 = left, 2 = middle, 3 = right //shiftclickOrig.type = "click"; // "mousedown" ? shiftclickOrig.currentTarget = target; shiftclickOrig.shiftKey = true; let shiftclick = jQ.Event("click"); //shiftclick.type = "click"; // "mousedown" ? shiftclick.which = 1; // 1 = left, 2 = middle, 3 = right shiftclick.shiftKey = true; shiftclick.currentTarget = target; shiftclick.originalEvent = shiftclickOrig; //document.ET_Util_Log(shiftclick); return shiftclick; }; if (!String.prototype.replaceAll) String.prototype.replaceAll = function(search, replace) { return ((replace === undefined) ? this.toString() : this.replace(new RegExp('[' + search + ']', 'g'), replace)); }; if (!String.prototype.startsWith) String.prototype.startsWith = function(search, pos) { return this.substr(((!pos) || (pos < 0)) ? 0 : +pos, search.length) === search; }; CInt = function(v) { try { if (!isNaN(v)) return Math.floor(v); if (typeof v === 'undefined') return parseInt(0); if (v === null) return parseInt(0); let t = parseInt(v); if (isNaN(t)) return parseInt(0); return Math.floor(t); } catch (err) { } return parseInt(0); }; CDbl = function(v) { try { if (!isNaN(v)) return parseFloat(v); if (typeof v === 'undefined') return parseFloat(0.0); if (v === null) return parseFloat(0.0); let t = parseFloat(v); if (isNaN(t)) return parseFloat(0.0); return t; } catch (err) { } return parseFloat(0.0); }; // dup of String.prototype.startsWith, but uses indexOf() instead of substr() startsWith = function (haystack, needle) { return (needle === "") || (haystack.indexOf(needle) === 0); }; endsWith = function (haystack, needle) { return (needle === "") || (haystack.substring(haystack.length - needle.length) === needle); }; Chopper = function(sText, sSearch, sEnd) { let sIntermediate = ""; if (sSearch === "") sIntermediate = sText.substring(0, sText.length); else { let iIndexStart = sText.indexOf(sSearch); if (iIndexStart === -1) return sText; sIntermediate = sText.substring(iIndexStart + sSearch.length); } if (sEnd === "") return sIntermediate; let iIndexEnd = sIntermediate.indexOf(sEnd); return (iIndexEnd === -1) ? sIntermediate : sIntermediate.substring(0, iIndexEnd); }; ChopperBlank = function(sText, sSearch, sEnd) { let sIntermediate = ""; if (sSearch === "") sIntermediate = sText.substring(0, sText.length); else { let iIndexStart = sText.indexOf(sSearch); if (iIndexStart === -1) return ""; sIntermediate = sText.substring(iIndexStart + sSearch.length); } if (sEnd === "") return sIntermediate; let iIndexEnd = sIntermediate.indexOf(sEnd); return (iIndexEnd === -1) ? "" : sIntermediate.substring(0, iIndexEnd); }; CondenseSpacing = function(text) { while (text.indexOf(" ") !== -1) text = text.replace(" ", " "); return text; }; // pad available both ways as pad(string, width, [char]) or string.pad(width, [char]) pad = function(sText, iWidth, sChar) { sChar = ((sChar !== undefined) ? sChar : ('0')); sText = sText.toString(); return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText)); }; if (!String.prototype.pad) String.prototype.pad = function(iWidth, sChar) { sChar = ((sChar !== undefined) ? sChar : ('0')); sText = sText.toString(); return ((sText.length >= iWidth) ? (sText) : (new Array(iWidth - sText.length + 1).join(sChar) + sText)); }; is_visible = (function () { var x = window.pageXOffset ? window.pageXOffset + window.innerWidth - 1 : 0, y = window.pageYOffset ? window.pageYOffset + window.innerHeight - 1 : 0, relative = !!((!x && !y) || !document.elementFromPoint(x, y)); function inside(child, parent) { while(child){ if (child === parent) return true; child = child.parentNode; } return false; } return function (elem) { if ( hidden || elem.offsetWidth==0 || elem.offsetHeight==0 || elem.style.visibility=='hidden' || elem.style.display=='none' || elem.style.opacity===0 ) return false; var rect = elem.getBoundingClientRect(); if (relative) { if (!inside(document.elementFromPoint(rect.left + elem.offsetWidth/2, rect.top + elem.offsetHeight/2),elem)) return false; } else if ( !inside(document.elementFromPoint(rect.left + elem.offsetWidth/2 + window.pageXOffset, rect.top + elem.offsetHeight/2 + window.pageYOffset), elem) || ( rect.top + elem.offsetHeight/2 < 0 || rect.left + elem.offsetWidth/2 < 0 || rect.bottom - elem.offsetHeight/2 > (window.innerHeight || document.documentElement.clientHeight) || rect.right - elem.offsetWidth/2 > (window.innerWidth || document.documentElement.clientWidth) ) ) return false; if (window.getComputedStyle || elem.currentStyle) { var el = elem, comp = null; while (el) { if (el === document) {break;} else if(!el.parentNode) return false; comp = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle; if (comp && (comp.visibility=='hidden' || comp.display == 'none' || (typeof comp.opacity !=='undefined' && comp.opacity != 1))) return false; el = el.parentNode; } } return true; }; })(); //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// ////////////// ** common_ET.js -- DO NOT MODIFY ** ///////////// if (window.ET === undefined) window.ET = { }; if ((window.ET.MCMF === undefined) || (CDbl(window.ET.MCMF.version) < 1.04)) // MeanCloud mod framework { window.ET.MCMF = { version: 1.04, TryingToLoad: false, WantDebug: false, WantFasterAbilityCDs: false, InBattle: false, FinishedLoading: false, Initialized: false, AbilitiesReady: false, InitialAbilityCheck: true, TimeLeftOnCD: 9999, TimeLastFight: 0, CombatID: undefined, BattleID: undefined, ToastMessageSuccess: function(msg) { toastr.success(msg); }, ToastMessageWarning: function(msg) { toastr.warning(msg); }, EventSubscribe: function(sEventName, fnCallback, sNote) { if (window.ET.MCMF.EventSubscribe_events === undefined) window.ET.MCMF.EventSubscribe_events = []; let newEvtData = {}; newEvtData.name = ((!sEventName.startsWith("ET:")) ? ("ET:" + sEventName) : (sEventName)); newEvtData.callback = fnCallback; newEvtData.note = sNote; window.ET.MCMF.EventSubscribe_events.push(newEvtData); /* jQ("div#ET_meancloud_bootstrap").off("ET:" + sEventName.trim()).on("ET:" + sEventName.trim(), function() { window.ET.MCMF.EventSubscribe_events.forEach(function(oThisEvent) { if (sEventName === oThisEvent.name) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")")); oThisEvent.callback(); } }); }); */ if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Added event subscription '" + sEventName + "'!" + ((sNote === undefined) ? "" : " (" + sNote + ")")); }, EventTrigger: function(sEventName) { //jQ("div#ET_meancloud_bootstrap").trigger(sEventName); if (window.ET.MCMF.EventSubscribe_events === undefined) return; window.ET.MCMF.EventSubscribe_events.forEach(function(oThisEvent) { if (sEventName === oThisEvent.name) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")")); try { oThisEvent.callback(); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Exception: " + err); } } }); }, Log: function(msg) { try { let now_time = new Date(); let timestamp = (now_time.getMonth() + 1).toString() + "/" + now_time.getDate().toString() + "/" + (now_time.getYear() + 1900).toString() + " " + ((now_time.getHours() === 0) ? (12) : ((now_time.getHours() > 12) ? (now_time.getHours() - 12) : (now_time.getHours()))).toString() + ":" + now_time.getMinutes().toString().padStart(2, "0") + ":" + now_time.getSeconds().toString().padStart(2, "0") + ((now_time.getHours() < 12) ? ("am") : ("pm")) + " :: "; console.log(timestamp.toString() + msg); } catch (err) { } }, Time: function() // returns time in milliseconds (not seconds!) { return CInt((new Date()).getTime()); }, SubscribeToGameChannel: function(channel_name) { let oChannel; try { channel_name = channel_name.toString().trim(); let bAlreadySubscribed = false; jQuery.makeArray(Object.keys(Package.meteor.global.Accounts.connection._subscriptions).map(key => Package.meteor.global.Accounts.connection._subscriptions[key])).forEach(function(oThisConnection) { try { if (oThisConnection.name === channel_name) bAlreadySubscribed = true; } catch (err) { } }); if (!bAlreadySubscribed) { Meteor.subscribe(channel_name); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Subscribed to channel '" + channel_name + "'"); } //else if (ET.MCMF.WantDebug) // window.ET.MCMF.Log("Meteor::Already subscribed to channel '" + channel_name + "'"); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in SubscribeToGameChannel(\"" + channel_name + "\")"); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err); } return oChannel; }, IsNewCombatTab: function() { try { if (window.location.href.indexOf("/newCombat") !== -1) { return true; } } catch (err) { } return false; }, GetActiveTab: function() { let active_tab = ""; /* try { active_tab = jQuery(jQuery("a.active").get(0)).text().trim().toLowerCase(); if (active_tab.length === 0) throw "Invalid active tab"; if (active_tab === "mine") active_tab = "mining"; if (active_tab === "craft") active_tab = "crafting"; if (active_tab === "battle") active_tab = "combat"; if (active_tab === "woodcut") active_tab = "woodcutting"; if (active_tab === "farm") active_tab = "farming"; if (active_tab === "inscribe") active_tab = "inscription"; //if (active_tab === "inscription") active_tab = "inscription"; //if (active_tab === "magic") active_tab = "magic"; //if (active_tab === "shop") active_tab = "shop"; } catch (err) { */ if (window.location.href.indexOf("/mining") !== -1) active_tab = "mining"; if (window.location.href.indexOf("/crafting") !== -1) active_tab = "crafting"; if (window.location.href.indexOf("/combat") !== -1) active_tab = "combat"; if (window.location.href.indexOf("/newCombat") !== -1) active_tab = "combat"; if (window.location.href.indexOf("/woodcutting") !== -1) active_tab = "woodcutting"; if (window.location.href.indexOf("/farming") !== -1) active_tab = "farming"; if (window.location.href.indexOf("/inscription") !== -1) active_tab = "inscription"; if (window.location.href.indexOf("/magic") !== -1) active_tab = "magic"; if (window.location.href.indexOf("/faq") !== -1) active_tab = "faq"; if (window.location.href.indexOf("/chat") !== -1) active_tab = "chat"; if (window.location.href.indexOf("/skills") !== -1) active_tab = "skills"; if (window.location.href.indexOf("/achievements") !== -1) active_tab = "achievements"; if (window.location.href.indexOf("/updates") !== -1) active_tab = "updates"; /* } */ return active_tab; }, GetActiveTabSection: function() { let active_tab_section = ""; try { let active_tab = window.ET.MCMF.GetActiveTab(); if (active_tab === "mining") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.miningTab; if (active_tab === "crafting") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.craftingFilter; if (active_tab === "combat") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.combatTab; if (active_tab === "farming") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.farmingTab; if (active_tab === "inscription") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.inscriptionFilter; if (active_tab === "achievements") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.achievementTab; if (active_tab === "magic") active_tab_section = Meteor.connection._stores.users._getCollection().find().fetch()[0].uiState.magicTab; active_tab_section = active_tab_section.trim().toLowerCase(); if (active_tab_section === "minepit") active_tab_section = "mine pit"; if (active_tab_section === "personalquest") active_tab_section = "personal quest"; if (active_tab_section === "tower") active_tab_section = "the tower"; if (active_tab_section === "battlelog") active_tab_section = "battle log"; if (active_tab_section === "pigment") active_tab_section = "pigments"; if (active_tab_section === "book") active_tab_section = "books"; if (active_tab_section === "magic_book") active_tab_section = "magic books"; if (active_tab_section === "spellbook") active_tab_section = "spell book"; if (active_tab_section.length === 0) throw "Invalid active tab section"; } catch (err) { try { active_tab_section = jQuery(jQuery("a.active").get(1)).text().trim().toLowerCase(); if (active_tab_section.length === 0) throw "Invalid active tab section"; } catch (err) { } } return active_tab_section; }, CallGameCmd: function() { try { if (arguments.length > 0) { let cmd = arguments[0]; let fnc = function() { }; if (arguments.length === 1) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with no data"); Package.meteor.Meteor.call(cmd, fnc); } else { let data1, data2, data3, data4; if (typeof arguments[arguments.length - 1] === "function") { fnc = arguments[arguments.length - 1]; if (arguments.length >= 3) data1 = arguments[1]; if (arguments.length >= 4) data2 = arguments[2]; if (arguments.length >= 5) data3 = arguments[3]; if (arguments.length >= 6) data4 = arguments[4]; } else { if (arguments.length >= 2) data1 = arguments[1]; if (arguments.length >= 3) data2 = arguments[2]; if (arguments.length >= 4) data3 = arguments[3]; if (arguments.length >= 5) data4 = arguments[4]; } if (data1 === undefined) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with no data"); Package.meteor.Meteor.call(cmd, fnc); } else if (data2 === undefined) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + " }"); Package.meteor.Meteor.call(cmd, data1, fnc); } else if (data3 === undefined) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + " }"); Package.meteor.Meteor.call(cmd, data1, data2, fnc); } else if (data4 === undefined) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + ", " + JSON.stringify(data3) + " }"); Package.meteor.Meteor.call(cmd, data1, data2, data3, fnc); } else { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Calling: '" + cmd + "' with { " + JSON.stringify(data1) + ", " + JSON.stringify(data2) + ", " + JSON.stringify(data3) + ", " + JSON.stringify(data4) + " }"); Package.meteor.Meteor.call(cmd, data1, data2, data3, data4, fnc); } } } else if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Warning, CallGameCmd() with no arguments!"); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in CallGameCmd()"); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err); } }, SendGameCmd: function(cmd) { try { Meteor.connection._send(cmd); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Sending: " + JSON.stringify(cmd)); } catch (err) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("Meteor::Exception in SendGameCmd(" + JSON.stringify(cmd) + ")"); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log(err); } }, FasterAbilityUpdates: function() { try { window.ET.MCMF.SubscribeToGameChannel("abilities"); if ((window.ET.MCMF.WantFasterAbilityCDs) && (window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.InBattle) && (!window.ET.MCMF.AbilitiesReady)) window.ET.MCMF.CallGameCmd("abilities.gameUpdate"); } catch (err) { } setTimeout(window.ET.MCMF.FasterAbilityUpdates, 2000); }, PlayerInCombat: function() { return ((window.ET.MCMF.InBattle) || ((time_val() - window.ET.MCMF.TimeLastFight) < 3)); }, AbilityCDTrigger: function() { try { if ((window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.PlayerInCombat())) { iTotalCD = 0; iTotalCDTest = 0; iHighestCD = 0; window.ET.MCMF.GetAbilities().forEach(function(oThisAbility) { if (oThisAbility.equipped) { if (parseInt(oThisAbility.currentCooldown) > 0) { iTotalCD += parseInt(oThisAbility.currentCooldown); if (iHighestCD < parseInt(oThisAbility.currentCooldown)) iHighestCD = parseInt(oThisAbility.currentCooldown); } } iTotalCDTest += parseInt(oThisAbility.cooldown); }); if ((iTotalCDTest > 0) && (iTotalCD === 0)) { if (!window.ET.MCMF.AbilitiesReady) { if (!window.ET.MCMF.InitialAbilityCheck) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->"); window.ET.MCMF.EventTrigger("ET:abilitiesReady"); } } window.ET.MCMF.AbilitiesReady = true; window.ET.MCMF.TimeLeftOnCD = 0; } else { window.ET.MCMF.AbilitiesReady = false; window.ET.MCMF.TimeLeftOnCD = iHighestCD; } window.ET.MCMF.InitialAbilityCheck = false; } else { window.ET.MCMF.AbilitiesReady = false; window.ET.MCMF.TimeLeftOnCD = 9999; } } catch (err) { } setTimeout(window.ET.MCMF.AbilityCDTrigger, 500); }, InitMeteorTriggers: function() { if ((Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined)) { setTimeout(window.ET.MCMF.InitMeteorTriggers, 100); return; } Package.meteor.Meteor.connection._stream.on('message', function(sMeteorRawData) { if (window.ET.MCMF.CombatID === undefined) window.ET.MCMF.GetPlayerCombatData(); try { oMeteorData = JSON.parse(sMeteorRawData); ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // BACKUP TO RETRIEVE USER AND COMBAT IDS // if (oMeteorData.collection === "users") if ((window.ET.MCMF.UserID === undefined) || (window.ET.MCMF.UserID.length !== 17)) window.ET.MCMF.UserID = oMeteorData.id; if (oMeteorData.collection === "combat") if ((window.ET.MCMF.CombatID === undefined) || (window.ET.MCMF.CombatID.length !== 17)) if (oMeteorData.fields.owner === window.ET.MCMF.UserID) window.ET.MCMF.CombatID = oMeteorData.id; // ///////////////////////////////////////////////////////////////////////////////////////////////////////// if (window.ET.MCMF.FinishedLoading) { if (oMeteorData.collection === "battlesList") { window.ET.MCMF.IsDemon = false; window.ET.MCMF.AbilitiesReady = false; if ((oMeteorData.msg === "added") || (oMeteorData.msg === "removed")) { window.ET.MCMF.InBattle = (oMeteorData.msg === "added"); if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")) + " -->"); window.ET.MCMF.EventTrigger("ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End"))); } } if ((oMeteorData.collection === "battles") && (oMeteorData.msg === "added")) { if (oMeteorData.fields.finished) { window.ET.MCMF.WonLast = oMeteorData.fields.win; window.ET.MCMF.TimeLastFight = time_val(); //if (!oMeteorData.fields.win) // window.ET.MCMF.HP = 0; if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")) + " -->"); window.ET.MCMF.EventTrigger("ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost"))); } } } try { if (window.ET.MCMF.FinishedLoading) { if (oMeteorData.id) { if (oMeteorData.id.startsWith("battles-")) { if (oMeteorData.msg !== "removed") { battleID = oMeteorData.id; battleData = JSON.parse(oMeteorData.fields.value); jQ.makeArray(battleData.units).forEach(function(currentPlayer) { try { if (currentPlayer.name === window.ET.MCMF.UserName) { window.ET.MCMF.PlayerUnitData = currentPlayer; jQ.makeArray(currentPlayer.buffs).forEach(function(currentBuff) { try { if (currentBuff.id === "demons_heart") { if (currentBuff.data.active) { if (!window.ET.MCMF.IsDemon) { window.ET.MCMF.IsDemon = true; if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:combat:buffDemon -->"); window.ET.MCMF.EventTrigger("ET:combat:buffDemon"); //jQ("div#ET_meancloud_bootstrap").trigger("ET:combat:buffDemon"); } } } } catch (err) { } }); return true; // break out of forEach() } } catch (err) { } }); } } } } } catch (err) { } } catch (err) { } }); }, PlayerHP: function() { if (!window.ET.MCMF.PlayerInCombat()) return window.ET.MCMF.GetPlayerCombatData(); return window.ET.MCMF.PlayerUnitData.stats.health; }, PlayerHPMax: function() { if (!window.ET.MCMF.PlayerInCombat()) return window.ET.MCMF.GetPlayerCombatData(); return window.ET.MCMF.PlayerUnitData.stats.healthMax; }, PlayerEnergy: function() { if (!window.ET.MCMF.PlayerInCombat()) return window.ET.MCMF.GetPlayerCombatData(); return window.ET.MCMF.PlayerUnitData.stats.energy; }, AbilityCDCalc: function() { iTotalCD = 0; iTotalCDTest = 0; iHighestCD = 0; window.ET.MCMF.GetAbilities().forEach(function(oThisAbility) { if (oThisAbility.equipped) { if (parseInt(oThisAbility.currentCooldown) > 0) { iTotalCD += parseInt(oThisAbility.currentCooldown); if (iHighestCD < parseInt(oThisAbility.currentCooldown)) iHighestCD = parseInt(oThisAbility.currentCooldown); } } iTotalCDTest += parseInt(oThisAbility.cooldown); }); if ((iTotalCDTest > 0) && (iTotalCD === 0)) { if (!window.ET.MCMF.AbilitiesReady) { if (!window.ET.MCMF.InitialAbilityCheck) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:abilitiesReady -->"); window.ET.MCMF.EventTrigger("ET:abilitiesReady"); //jQ("div#ET_meancloud_bootstrap").trigger("ET:abilitiesReady"); } } window.ET.MCMF.AbilitiesReady = true; window.ET.MCMF.TimeLeftOnCD = 0; } else { window.ET.MCMF.AbilitiesReady = false; window.ET.MCMF.TimeLeftOnCD = iHighestCD; } window.ET.MCMF.InitialAbilityCheck = false; }, GetPlayerCombatData: function() { let oCombatPlayerData; try { window.ET.MCMF.CombatID = undefined; Meteor.connection._stores.combat._getCollection().find().fetch().forEach(function(oThisCombatUnit) { if (oThisCombatUnit.owner === window.ET.MCMF.UserID) { oCombatPlayerData = oThisCombatUnit; window.ET.MCMF.CombatID = oCombatPlayerData._id; if (!window.ET.MCMF.PlayerInCombat()) window.ET.MCMF.PlayerUnitData = oCombatPlayerData; } }); } catch (err) { } return oCombatPlayerData; }, GetAbilities: function() { return Meteor.connection._stores.abilities._getCollection().find().fetch()[0].learntAbilities; }, GetAdventures: function() { let oAdventureDetails = { AllAdventures: [], ShortAdventures: [], LongAdventures: [], EpicAdventures: [], PhysicalAdventures: [], MagicalAdventures: [], ActiveAdventures: [], CurrentAdventure: undefined }; // oThisAdventure // .duration {duration in seconds} (integer) // .endDate {end date/time} (Date()) (property only exists if the adventure is ongoing) // .floor {corresponding Tower Floor} (integer) // .icon "{imageofbattle.ext}" (string) // .id "{guid}" (13-digit alphanumeric string) // .length "short" / "long" / "epic" (string) // .level {general level} (integer) // .name "{Name of Battle}" (string) // .room {corresponding Tower Room in Tower Floor} (integer) // .type "physical" / "magic" (string) // .startDate {start date/time} (Date()) (property only exists if the adventure is ongoing) window.ET.MCMF.GetAdventures_raw().forEach(function(oThisAdventure) { try { oAdventureDetails.AllAdventures.push(oThisAdventure); if (oThisAdventure.length === "short") oAdventureDetails.ShortAdventures .push(oThisAdventure); if (oThisAdventure.length === "long") oAdventureDetails.LongAdventures .push(oThisAdventure); if (oThisAdventure.length === "epic") oAdventureDetails.EpicAdventures .push(oThisAdventure); if (oThisAdventure.type === "physical") oAdventureDetails.PhysicalAdventures.push(oThisAdventure); if (oThisAdventure.type === "magic") oAdventureDetails.MagicalAdventures .push(oThisAdventure); if (oThisAdventure.endDate !== undefined) oAdventureDetails.ActiveAdventures .push(oThisAdventure); } catch (err) { } }); oAdventureDetails.AllAdventures.sort(function(advA, advB) { if ((advA.startDate === undefined) && (advB.startDate !== undefined)) return 1; if ((advA.startDate !== undefined) && (advB.startDate === undefined)) return -1; if ((advA.startDate !== undefined) && (advB.startDate !== undefined)) { if (advA.startDate > advB.startDate) return 1; if (advA.startDate < advB.startDate) return -1; } if (advA.duration > advB.duration) return 1; if (advA.duration < advB.duration) return -1; return 0; }); oAdventureDetails.ActiveAdventures.sort(function(advA, advB) { if (advA.startDate > advB.startDate) return 1; if (advA.startDate < advB.startDate) return -1; return 0; }); oAdventureDetails.PhysicalAdventures.sort(function(advA, advB) { if (advA.duration > advB.duration) return 1; if (advA.duration < advB.duration) return -1; return 0; }); oAdventureDetails.MagicalAdventures.sort(function(advA, advB) { if (advA.duration > advB.duration) return 1; if (advA.duration < advB.duration) return -1; return 0; }); if (oAdventureDetails.ActiveAdventures.length > 0) oAdventureDetails.CurrentAdventure = oAdventureDetails.ActiveAdventures[0]; return oAdventureDetails; }, GetAdventures_raw: function() { return Meteor.connection._stores.adventures._getCollection().find().fetch()[0].adventures; }, GetChats: function() { return Meteor.connection._stores.simpleChats._getCollection().find().fetch(); }, GetItems: function() { return Meteor.connection._stores.items._getCollection().find().fetch(); }, GetSkills: function() { return Meteor.connection._stores.skills._getCollection().find().fetch(); }, // need a better way to check if the game has loaded basic data, but this is fine for now Setup: function() { if ((!window.ET.MCMF.TryingToLoad) && (!window.ET.MCMF.FinishedLoading)) { // use whatever version of jQuery available to us $("body").append("<div id=\"ET_meancloud_bootstrap\" style=\"visibility: hidden; display: none;\"></div>"); window.ET.MCMF.TryingToLoad = true; window.ET.MCMF.Setup_Initializer(); } }, Setup_Initializer: function() { // wait for Meteor availability if ((Package === undefined) || (Package.meteor === undefined) || (Package.meteor.Meteor === undefined) || (Package.meteor.Meteor.connection === undefined) || (Package.meteor.Meteor.connection._stream === undefined)) { setTimeout(window.ET.MCMF.Setup_Initializer, 10); return; } if (!window.ET.MCMF.Initialized) { window.ET.MCMF.Initialized = true; window.ET.MCMF.Setup_SendDelayedInitializer(); window.ET.MCMF.InitMeteorTriggers(); window.ET.MCMF.Setup_remaining(); } }, Setup_SendDelayedInitializer: function() { try { jQ("div#ET_meancloud_bootstrap").trigger("ET:initialized"); window.ET.MCMF.EventTrigger("ET:initialized"); //if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:initialized -->"); } catch (err) { setTimeout(window.ET.MCMF.Setup_SendDelayedInitializer, 100); } }, Setup_remaining: function() { try { if (Meteor === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized"; if (Meteor.connection === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized"; if (Meteor.connection._userId === undefined) throw "[MCMF Setup] Not loaded yet: Meteor not initialized"; window.ET.MCMF.UserID = Meteor.connection._userId; window.ET.MCMF.UserName = Meteor.connection._stores.users._getCollection()._collection._docs._map[window.ET.MCMF.UserID].username; window.ET.MCMF.GetPlayerCombatData(); if (window.ET.MCMF.GetAbilities().length < 0) throw "[MCMF Setup] Not loaded yet: no abilities"; if (window.ET.MCMF.GetItems().length < 0) throw "[MCMF Setup]Not loaded yet: no items"; if (window.ET.MCMF.GetChats().length < 0) throw "[MCMF Setup]Not loaded yet: no chats"; if (window.ET.MCMF.GetSkills().length < 0) throw "[MCMF Setup]Not loaded yet: no skills"; // if the above is all good, then this should be no problem: window.ET.MCMF.AbilityCDTrigger(); // set up ability CD trigger window.ET.MCMF.AbilityCDCalc(); window.ET.MCMF.FasterAbilityUpdates(); // set up faster ability updates (do not disable, this is controlled via configurable setting) // trigger finished-loading event if (!window.ET.MCMF.FinishedLoading) { if (window.ET.MCMF.WantDebug) window.ET.MCMF.Log("<-- triggering ET:loaded -->"); window.ET.MCMF.EventTrigger("ET:loaded"); window.ET.MCMF.FinishedLoading = true; } } catch (err) // any errors and we retry setup { if (err.toString().indexOf("[MCMF Setup]") !== -1) { window.ET.MCMF.Log("ET MCMF setup exception"); window.ET.MCMF.Log(err); } setTimeout(window.ET.MCMF.Setup_remaining, 500); } }, // Ready means the mod framework has been initialized, but Meteor is not yet available Ready: function(fnCallback, sNote) { if (!window.ET.MCMF.Initialized) window.ET.MCMF.EventSubscribe("initialized", fnCallback, sNote); else fnCallback(); }, // Loaded means the mod framework and Meteor are fully loaded and available Loaded: function(fnCallback, sNote) { if (!window.ET.MCMF.FinishedLoading) window.ET.MCMF.EventSubscribe("loaded", fnCallback, sNote); else fnCallback(); }, }; window.ET.MCMF.Setup(); } //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// ////////// ** CORE SCRIPT STARTUP -- DO NOT MODIFY ** ////////// function LoadJQ(callback) { 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() { var subscript=document.createElement("script");subscript.textContent="window.jQ=jQuery.noConflict(true);("+callback.toString()+")();";document.body.appendChild(subscript); }, !1);document.body.appendChild(script); } else callback(); } LoadJQ(startup); ////////////////////////////////////////////////////////////////