diff --git a/code/portal_detail_display.js b/code/portal_detail_display.js
index effd9fb1..1b81b8d3 100644
--- a/code/portal_detail_display.js
+++ b/code/portal_detail_display.js
@@ -40,8 +40,11 @@ window.renderPortalDetails = function(guid) {
// collect and html-ify random data
var randDetails = [
- playerText, sinceText, getRangeText(d), getEnergyText(d),
- linksText, getAvgResoDistText(d), linkedFields, getAttackApGainText(d)
+ playerText, sinceText,
+ getRangeText(d), getEnergyText(d),
+ linksText, getAvgResoDistText(d),
+ linkedFields, getAttackApGainText(d),
+ getHackDetailsText(d), getMitigationText(d)
];
randDetails = '
' + genFourColumnTable(randDetails) + '
';
diff --git a/code/portal_detail_display_tools.js b/code/portal_detail_display_tools.js
index e14aadcd..a1196d60 100644
--- a/code/portal_detail_display_tools.js
+++ b/code/portal_detail_display_tools.js
@@ -146,7 +146,7 @@ window.getEnergyText = function(d) {
window.getAvgResoDistText = function(d) {
var avgDist = Math.round(10*getAvgResoDist(d))/10;
- return ['reso dist', avgDist + ' m'];
+ return ['res dist', avgDist + ' m'];
}
window.getResonatorDetails = function(d) {
@@ -226,8 +226,46 @@ window.getAttackApGainText = function(d) {
t += 'Enemy AP:\t' + breakdown.enemyAp + '\n';
t += ' Destroy AP:\t' + breakdown.destroyAp + '\n';
t += ' Capture AP:\t' + breakdown.captureAp + '\n';
- return '' + digits(text) + '';
+ return '' + text + '';
}
- return [tt('AP Gain'), tt(totalGain)];
+ return [tt('AP Gain'), tt(digits(totalGain))];
+}
+
+
+window.getHackDetailsText = function(d) {
+ var hackDetails = getPortalHackDetails(d);
+
+ var shortHackInfo = hackDetails.hacks+' @ '+formatInterval(hackDetails.cooldown);
+
+ function tt(text) {
+ var t = 'Hacks available every 4 hours\n';
+ t += 'Hack count:\t'+hackDetails.hacks+'\n';
+ t += 'Cooldown time:\t'+formatInterval(hackDetails.cooldown)+'\n';
+ t += 'Burnout time:\t'+formatInterval(hackDetails.burnout)+'\n';
+
+ return ''+text+'';
+ }
+
+ return [tt('hacks'), tt(shortHackInfo)];
+}
+
+
+window.getMitigationText = function(d) {
+ var mitigationDetails = getPortalMitigationDetails(d);
+
+ var mitigationShort = mitigationDetails.total;
+ if (mitigationDetails.excess) mitigationShort += ' (+'+mitigationDetails.excess+')';
+
+ function tt(text) {
+ var t = 'Mitigation:\t'+mitigationDetails.total+'\n';
+ t += 'Shields:\t'+mitigationDetails.shields+'\n';
+ t += 'Links:\t'+mitigationDetails.links+'\n';
+ t += 'Excess:\t'+mitigationDetails.excess+'\n';
+
+ return ''+text+'';
+ }
+
+ // 'mitigation' doesn't quite fit in the space.
+ return [tt('mitig…'), tt(mitigationShort)];
}
diff --git a/code/portal_info.js b/code/portal_info.js
index bdb8d415..a6a5bc01 100644
--- a/code/portal_info.js
+++ b/code/portal_info.js
@@ -276,3 +276,31 @@ window.getPortalMitigationDetails = function(d) {
return mitigation;
}
+
+
+window.getPortalHackDetails = function(d) {
+
+ var heatsinks = getPortalModsByType(d, 'HEATSINK');
+ var multihacks = getPortalModsByType(d, 'MULTIHACK');
+
+ // first mod of type is fully effective, the others are only 50% effective
+ var effectivenessReduction = [ 1, 0.5, 0.5, 0.5 ];
+
+ var cooldownTime = 300; // 5 mins - 300 seconds
+
+ $.each(heatsinks, function(index,mod) {
+ var hackSpeed = parseInt(mod.stats.HACK_SPEED)/1000000;
+ cooldownTime = Math.round(cooldownTime * (1 - hackSpeed * effectivenessReduction[index]));
+ });
+
+ var numHacks = 4; // default hacks
+
+ $.each(multihacks, function(index,mod) {
+ var extraHacks = parseInt(mod.stats.BURNOUT_INSULATION);
+ numHacks = numHacks + (extraHacks * effectivenessReduction[index]);
+ });
+
+ return {cooldown: cooldownTime, hacks: numHacks, burnout: cooldownTime*(numHacks-1)};
+}
+
+
diff --git a/code/utils_misc.js b/code/utils_misc.js
index e02437c9..e559a974 100644
--- a/code/utils_misc.js
+++ b/code/utils_misc.js
@@ -308,6 +308,21 @@ window.unixTimeToHHmm = function(time) {
return h + ':' + s;
}
+window.formatInterval = function(seconds) {
+
+ var h = Math.floor(seconds / 3600);
+ var m = Math.floor((seconds % 3600) / 60);
+ var s = seconds % 60;
+
+ var text = '';
+ if (h > 0) text += h+'h';
+ if (m > 0) text += m+'m';
+ if (s > 0 || text == '') text += s+'s';
+
+ return text;
+}
+
+
window.rangeLinkClick = function() {
if(window.portalRangeIndicator)
window.map.fitBounds(window.portalRangeIndicator.getBounds());