diff --git a/plugins/ap-list.user.js b/plugins/ap-list.user.js
index f2af503a..836a8206 100644
--- a/plugins/ap-list.user.js
+++ b/plugins/ap-list.user.js
@@ -1,11 +1,11 @@
// ==UserScript==
// @id iitc-plugin-ap-list@xelio
// @name iitc: AP List
-// @version 0.3
+// @version 0.4
// @namespace https://github.com/breunigs/ingress-intel-total-conversion
// @updateURL https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
// @downloadURL https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
-// @description List top 10 portals by AP of either faction. Hover over AP will show breakdown of AP. Click on portal name will select the portal. Double click on portal name will zoom to and select portal. Portals before zooming in will be cached and count in top portal. They will be cleared if you click the "↻ R" or move out of the area.
+// @description List top 10 portals by AP of either faction. Other functions and controls please refer to the Userguide. (https://github.com/breunigs/ingress-intel-total-conversion/wiki/Userguide-%28Main-Vanilla-IITC%29#wiki-pluginsAPListUserGuide)
// @include https://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// ==/UserScript==
@@ -36,6 +36,8 @@ window.plugin.apList.useCachedPortals = false;
window.plugin.apList.cacheBounds;
window.plugin.apList.cacheActiveZoomLevel;
+window.plugin.apList.destroyPortalsGuid = new Array();
+
window.plugin.apList.handleUpdate = function() {
if(!requests.isLastRequest('getThinnedEntitiesV2')) return;
@@ -45,22 +47,66 @@ window.plugin.apList.handleUpdate = function() {
// Generate html table from top portals
window.plugin.apList.updatePortalTable = function(side) {
+ var displayEnemy = (plugin.apList.displaySide === window.plugin.apList.SIDE_ENEMY);
+
var content = '
';
for(var i = 0; i < plugin.apList.topMaxCount; i++) {
var portal = plugin.apList.sortedPortals[side][i];
- content += ''
- + ''
- + (portal ? plugin.apList.getPortalLink(portal) : ' ')
- + ' | '
- + ''
- + (portal ? plugin.apList.getPortalApText(portal) : ' ')
- + ' | '
- + '
';
+ content += '';
+ // Only enemy portal list will display destroy checkbox
+ if(displayEnemy) {
+ content += ''
+ + (portal ? plugin.apList.getPortalDestroyCheckbox(portal) : ' ')
+ + ' | ';
+ }
+ content += ''
+ + (portal ? plugin.apList.getPortalLink(portal) : ' ')
+ + ' | '
+ + ''
+ + (portal ? plugin.apList.getPortalApText(portal) : ' ')
+ + ' | '
+ + '
';
}
content += "
";
$('div#ap-list-table').html(content);
}
+window.plugin.apList.getPortalDestroyCheckbox = function(portal) {
+ // Change background color to border color if portal selected for destroy
+ var style = 'width: 10px; height: 10px; border: 1px solid rgb(32, 168, 177); margin: 0 auto; '
+ + (plugin.apList.destroyPortalIndex(portal.guid) >= 0
+ ? 'background-color: rgb(32, 168, 177);'
+ : '');
+ var onClick = 'window.plugin.apList.destroyPortal(\'' + portal.guid + '\');';
+ // 3 div for centering checkbox horizontally and vertically,
+ // click event on outest div for people with not so good aiming
+ var div = '';
+ return div;
+}
+
+window.plugin.apList.destroyPortal = function(guid) {
+ // Add to destroyPortalsGuid if not yet added, remove if already added
+ var portalIndex = plugin.apList.destroyPortalIndex(guid);
+ if(portalIndex >= 0) {
+ plugin.apList.destroyPortalsGuid.splice(portalIndex, 1);
+ } else {
+ plugin.apList.destroyPortalsGuid.push(guid);
+ }
+
+ plugin.apList.updateSortedPortals();
+ plugin.apList.updatePortalTable(plugin.apList.displaySide);
+}
+
+// Return the index of portal in destroyPortalsGuid
+window.plugin.apList.destroyPortalIndex = function(guid) {
+ return $.inArray(guid, plugin.apList.destroyPortalsGuid);
+}
+
// Combine title and test
window.plugin.apList.getPortalApText = function(portal) {
var title = plugin.apList.getPortalApTitle(portal);
@@ -83,6 +129,7 @@ window.plugin.apList.getPortalApTitle = function(portal) {
t += 'Sum: ' + digits(playerApGain.totalAp) + ' AP';
} else {
t = 'Destroy & Capture:\n'
+ + 'R:' + playerApGain.resoCount + ' L:' + playerApGain.linkCount + ' CF:' + playerApGain.fieldCount + '\n'
+ 'Destroy AP\t=\t' + digits(playerApGain.destroyAp) + '\n'
+ 'Capture AP\t=\t' + digits(playerApGain.captureAp) + '\n'
+ 'Sum: ' + digits(playerApGain.totalAp) + ' AP';
@@ -99,9 +146,13 @@ window.plugin.apList.getPortalLink = function(portal) {
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+portal.guid+'\', ['+latlng+']);return false';
var perma = 'https://ingress.com/intel?latE6='+portal.locationE6.latE6
+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+portal.guid;
+ var style = plugin.apList.destroyPortalIndex(portal.guid) >= 0
+ ? 'font-style:italic'
+ : '';
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('',{
"class": 'help',
+ style: style,
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
@@ -155,6 +206,81 @@ window.plugin.apList.updateSortedPortals = function() {
return b.playerApGain.totalAp - a.playerApGain.totalAp;
});
});
+
+ // Modify sortedPortals if any portal selected for destroy
+ if(plugin.apList.destroyPortalsGuid.length > 0) {
+ plugin.apList.handleDestroyPortal()
+ }
+}
+
+// This function will make AP gain of field and link only count once if
+// one of the connected portal is selected for destroy
+window.plugin.apList.handleDestroyPortal = function() {
+ var enemy = window.plugin.apList.SIDE_ENEMY;
+ var destroyedLinks = {};
+ var destroyedFields = {};
+
+ // Clean up portal selected for destroy, remove from destroyPortalsGuid
+ // if portal not exist or change to friendly side
+ plugin.apList.destroyPortalsGuid = $.grep(plugin.apList.destroyPortalsGuid, function(portalGuid,ind) {
+ var portal = plugin.apList.cachedPortals[portalGuid];
+ if(!portal || plugin.apList.portalSide(portal) !== enemy) return false;
+ return true;
+ });
+
+ // Loop through portals from highest AP to lowest AP, matching links and fields to the
+ // portal only if the portal is selected for destroy and have highest AP.
+ // Matching info stores in "destroyedLinks" and "destroyedFields"
+ $.each(plugin.apList.sortedPortals[enemy], function(ind, portal) {
+ if(plugin.apList.destroyPortalIndex(portal.guid) < 0) return true;
+
+ $.each(portal.portalV2.linkedEdges || [], function(ind,link) {
+ // Skip if the link already matched with a portal
+ if(destroyedLinks[link.edgeGuid]) return true;
+ belongTo = {portalGuid: portal.guid};
+ destroyedLinks[link.edgeGuid] = belongTo;
+ });
+ $.each(portal.portalV2.linkedFields || [], function(ind,field) {
+ // Skip if the field already matched with a portal
+ if(destroyedFields[field]) return true;
+ belongTo = {portalGuid: portal.guid};
+ destroyedFields[field] = belongTo;
+ });
+ });
+
+ // Remove the link and field which was matched with another portal
+ var getApGainFunc = plugin.apList.playerApGainFunc[enemy];
+ $.each(plugin.apList.sortedPortals[enemy], function(ind, portal) {
+ // Filter out links which was matched with another portal
+ var newLinkedEdges = $.grep(portal.portalV2.linkedEdges || [], function(link,ind) {
+ if(!destroyedLinks[link.edgeGuid]) return true;
+ return (destroyedLinks[link.edgeGuid].portalGuid === portal.guid);
+ });
+ // Filter out fields which was matched with another portal
+ var newLinkedFields = $.grep(portal.portalV2.linkedFields || [], function(field,ind) {
+ if(!destroyedFields[field]) return true;
+ return (destroyedFields[field].portalGuid === portal.guid);
+ });
+
+ // Skip modifying portal if no link and field changed
+ if(newLinkedEdges.length === (portal.portalV2.linkedEdges || []).length
+ && newLinkedFields.length === (portal.portalV2.linkedFields || []).length)
+ return true;
+
+ // Clone the portal to avoid modifying original data in cachedPortal
+ var newPortal = $.extend(true, {}, portal);
+ // Assign new links and fields and calculate new playerApGain
+ if(portal.portalV2.linkedEdges) newPortal.portalV2.linkedEdges = newLinkedEdges;
+ if(portal.portalV2.linkedFields) newPortal.portalV2.linkedFields = newLinkedFields;
+ newPortal.playerApGain = getApGainFunc(newPortal);
+
+ plugin.apList.sortedPortals[enemy][ind] = newPortal;
+ });
+
+ // Sorting portals with updated AP
+ plugin.apList.sortedPortals[enemy].sort(function(a, b) {
+ return b.playerApGain.totalAp - a.playerApGain.totalAp;
+ });
}
window.plugin.apList.enableCache = function() {
@@ -271,7 +397,10 @@ window.plugin.apList.getAttackApGain = function(d) {
return {
totalAp: totalAp,
destroyAp: destroyAp,
- captureAp: captureAp
+ captureAp: captureAp,
+ resoCount: resoCount,
+ linkCount: linkCount,
+ fieldCount: fieldCount
}
}