// ==UserScript==
// @name Eternity Tower Stats UI
// @icon https://www.eternitytower.net/favicon.png
// @namespace http://mean.cloud/
// @version 1.15
// @description Adds stats to the UI for the Eternity Tower game
// @match http*://*.eternitytower.net/*
// @author psouza4@gmail.com
// @copyright 2017-2018, MeanCloud
// @run-at document-end
// ==/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()
{
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()
{
// Set background tasks
ET_StatsUIMod_DPSShow();
});
};
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;
///////////////////////////////////////////////////////////////////////////////////////
//
// Stat Descriptions
//
jQ(".PeteUI_TooltipStat").remove();
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>");
//
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//
// 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();
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*******************");
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, viewing profiles, etc.)
//
try
{
jQ("div.item-tooltip-content").each(function()
{
if (jQ(this).find("div.PeteUI_TooltipExp").length !== 0)
return;
sBareDamageRange = "";
sBareAttackSpeed = "";
sBareCriticalChance = "";
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();
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("Name: " + sItemName);
//console.log("Bare DPS: " + sBareDamageRange);
//console.log("Bare attack speed: " + sBareAttackSpeed);
//console.log("Bare crit chance: " + sBareCriticalChance);
//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))
{
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"
);
}
}
});
}
catch (err) { console.log("ERROR: " + err); }
//
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
//
// Combat Stats page (personal)
//
try
{
if (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/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)
{
if (oEl === undefined)
{
var shiftclick = jQ.Event("click");
shiftclick.shiftKey = true;
var shiftclickOrig = jQ.Event("click");
shiftclickOrig.shiftKey = true;
shiftclick.originalEvent = shiftclick;
return shiftclick;
}
jQ(oEl).trigger(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);
var 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);
var 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); };
ChopperBlank = function (sText, sSearch, sEnd)
{
var sIntermediate = "";
if (sSearch === "")
sIntermediate = sText.substring(0, sText.length);
else
{
var iIndexStart = sText.indexOf(sSearch);
if (iIndexStart === -1)
return "";
sIntermediate = sText.substring(iIndexStart + sSearch.length);
}
if (sEnd === "")
return sIntermediate;
var iIndexEnd = sIntermediate.indexOf(sEnd);
return (iIndexEnd === -1) ? sIntermediate : sIntermediate.substring(0, iIndexEnd);
};
CondenseSpacing = function(text)
{
while (text.indexOf(" ") !== -1)
text = text.replace(" ", " ");
return text;
};
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));
};
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) || !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(elementFromPoint(rect.left + elem.offsetWidth/2, rect.top + elem.offsetHeight/2),elem)) return false;
} else if (
!inside(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 || documentElement.clientHeight) ||
rect.right - elem.offsetWidth/2 > (window.innerWidth || 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) // MeanCloud mod framework
{
window.ET.MCMF =
{
TryingToLoad: false,
WantDebug: false,
WantFasterAbilityCDs: false,
InBattle: false,
FinishedLoading: false,
Initialized: false,
AbilitiesReady: false,
InitialAbilityCheck: true,
TimeLeftOnCD: 9999,
TimeLastFight: 0,
CombatID: undefined, // technically not required
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 = [];
var 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, index, array)
{
if (sEventName === oThisEvent.name)
{
if (window.ET.MCMF.WantDebug) console.log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")"));
oThisEvent.callback();
}
});
});
*/
if (window.ET.MCMF.WantDebug) console.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, index, array)
{
if (sEventName === oThisEvent.name)
{
if (window.ET.MCMF.WantDebug) console.log("FIRING '" + oThisEvent.name + "'!" + ((oThisEvent.note === undefined) ? "" : " (" + oThisEvent.note + ")"));
try { oThisEvent.callback(); } catch (err) { if (window.ET.MCMF.WantDebug) console.log("Exception: " + err); }
}
});
},
MeteorCall: function(sMethod, oParam1, oParam2, sMsgSuccess, sMsgFailure)
{
Package.meteor.Meteor.call("crafting.craftItem", sRecipeID, iBatchAmt, function(errResp)
{
if (errResp)
window.ET.MCMF.ToastMessageWarning(sMsgFailure);
else
window.ET.MCMF.ToastMessageSuccess(sMsgSuccess);
});
},
FasterAbilityUpdates: function()
{
try
{
if ((window.ET.MCMF.WantFasterAbilityCDs) && (window.ET.MCMF.FinishedLoading) && (!window.ET.MCMF.InBattle) && (!window.ET.MCMF.AbilitiesReady))
Meteor.call("abilities.gameUpdate", function(e, t) { });
}
catch (err) { }
setTimeout(window.ET.MCMF.FasterAbilityUpdates, 2000);
},
AbilityCDTrigger: function()
{
try
{
bStillInCombat = window.ET.MCMF.InBattle || ((time_val() - window.ET.MCMF.TimeLastFight) < 3);
if ((window.ET.MCMF.FinishedLoading) && (!bStillInCombat))
{
iTotalCD = 0;
iTotalCDTest = 0;
iHighestCD = 0;
window.ET.MCMF.GetAbilities().forEach(function(oThisAbility, index, array)
{
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) console.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;
}
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)
{
try
{
oDataTemp = Package.meteor.global.Accounts.connection._stores.combat._getCollection()._collection._docs._map;
window.ET.MCMF.CombatID = oDataTemp[Object.keys(oDataTemp)[0]]._id;
}
catch (err) { }
}
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.T_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) console.log("<-- triggering ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")) + " -->");
window.ET.MCMF.EventTrigger("ET:combat" + (((oMeteorData.msg === "added")) ? ("Start") : ("End")));
//jQ("div#ET_meancloud_bootstrap").trigger("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) console.log("<-- triggering ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")) + " -->");
window.ET.MCMF.EventTrigger("ET:combat" + ((oMeteorData.fields.win) ? ("Won") : ("Lost")));
//jQ("div#ET_meancloud_bootstrap").trigger("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, index, array)
{
try
{
if (currentPlayer.name === window.ET.MCMF.UserName)
{
jQ.makeArray(currentPlayer.buffs).forEach(function(currentBuff, index2, array2)
{
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) console.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) { }
try
{
//todo: use life data from Meteor vs captured meteor response data
oMeteorData = JSON.parse(sMeteorRawData);
if (oMeteorData.collection === "combat")
{
if ((oMeteorData.fields.owner === window.ET.MCMF.UserID) || (oMeteorData.id === window.ET.MCMF.CombatID))
{
window.ET.MCMF.HP = oMeteorData.fields.stats.health;
window.ET.MCMF.NRG = oMeteorData.fields.stats.energy;
}
}
}
catch (err) { }
});
},
AbilityCDCalc: function()
{
iTotalCD = 0;
iTotalCDTest = 0;
iHighestCD = 0;
window.ET.MCMF.GetAbilities().forEach(function(oThisAbility, index, array)
{
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) console.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;
},
GetAbilities: function()
{
return Object.keys(window.ET.MCMF.AbilityManager._collection._docs._map).map(key => window.ET.MCMF.AbilityManager._collection._docs._map[key])[0].learntAbilities;
},
GetAdventures: function()
{
return Object.keys(window.ET.MCMF.AdventureManager._collection._docs._map).map(key => window.ET.MCMF.AdventureManager._collection._docs._map[key])[0].adventures;
},
GetChats: function()
{
return Object.keys(window.ET.MCMF.ChatManager._collection._docs._map).map(key => window.ET.MCMF.ChatManager._collection._docs._map[key]);
},
GetItems: function()
{
return Object.keys(window.ET.MCMF.ItemManager._collection._docs._map).map(key => window.ET.MCMF.ItemManager._collection._docs._map[key]);
},
// 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) console.log("<-- triggering ET:initialized -->");
}
catch (err)
{
setTimeout(window.ET.MCMF.Setup_SendDelayedInitializer, 100);
}
},
Setup_remaining: function()
{
try
{
window.ET.MCMF.UserID = Package.meteor.global.Accounts.connection._userId;
window.ET.MCMF.UserName = Package.meteor.global.Accounts.connection._stores.users._getCollection()._collection._docs._map[Package.meteor.global.Accounts.connection._userId].username;
try
{
oDataTemp = Package.meteor.global.Accounts.connection._stores.combat._getCollection()._collection._docs._map;
window.ET.MCMF.CombatID = oDataTemp[Object.keys(oDataTemp)[0]]._id;
}
catch (err) { }
window.ET.MCMF.AbilityManager = Package.meteor.global.Accounts.connection._stores.abilities._getCollection();
window.ET.MCMF.AdventureManager = Package.meteor.global.Accounts.connection._stores.adventures._getCollection();
window.ET.MCMF.ChatManager = Package.meteor.global.Accounts.connection._stores.simpleChats._getCollection();
window.ET.MCMF.ItemManager = Package.meteor.global.Accounts.connection._stores.items._getCollection();
if (window.ET.MCMF.GetAbilities().length < 0) throw "Not loaded yet: no abilities";
if (window.ET.MCMF.GetItems().length < 0) throw "Not loaded yet: no items";
if (window.ET.MCMF.GetChats().length < 0) throw "Not loaded yet: no chats";
// 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) console.log("<-- triggering ET:loaded -->");
window.ET.MCMF.EventTrigger("ET:loaded");
//jQ("div#ET_meancloud_bootstrap").trigger("ET:loaded");
window.ET.MCMF.FinishedLoading = true;
}
}
catch (err)
{
// any errors and we retry setup
setTimeout(window.ET.MCMF.Setup_remaining, 500);
}
},
Loaded: function(fnCallback, sNote)
{
if (!window.ET.MCMF.FinishedLoading)
window.ET.MCMF.EventSubscribe("loaded", fnCallback, sNote);
else
fnCallback();
},
Ready: function(fnCallback, sNote)
{
if (!window.ET.MCMF.Initialized)
window.ET.MCMF.EventSubscribe("initialized", 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);
////////////////////////////////////////////////////////////////