Merge branch 'to-push' of github.com:nexushoratio/ingress-intel-total-conversion into to-push

Conflicts:
	plugins/portal-defense.user.js
	plugins/show-linked-portals.user.js
This commit is contained in:
Mike Castle
2013-12-02 02:18:03 -08:00
98 changed files with 11406 additions and 11373 deletions

0
plugins/add-kml.user.js Executable file → Normal file
View File

View File

@ -1,942 +1,15 @@
// ==UserScript==
// @id iitc-plugin-ap-list@xelio
// @name IITC plugin: AP List
// @category Info
// @category Deleted
// @version 0.5.7.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] List portals by AP of either faction or by effective level. Other functions and controls please refer to the Userguide.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.apList = function() {
};
window.plugin.apList.cachedPortals = {};
window.plugin.apList.SIDE_FRIENDLY = 0;
window.plugin.apList.SIDE_ENEMY = 1;
window.plugin.apList.displaySide = window.plugin.apList.SIDE_ENEMY;
window.plugin.apList.sides = new Array(2);
window.plugin.apList.sortedPortals = new Array(2);
window.plugin.apList.playerApGainFunc = new Array(2);
window.plugin.apList.SORT_BY_AP = 'AP';
window.plugin.apList.SORT_BY_EL = 'EL';
window.plugin.apList.sortBy = window.plugin.apList.SORT_BY_AP;
window.plugin.apList.SORT_ASC = 1;
window.plugin.apList.SORT_DESC = -1;
window.plugin.apList.sortOptions = {};
window.plugin.apList.currentPage = [1,1];
window.plugin.apList.totalPage = [1,1];
window.plugin.apList.portalPerPage = 10;
window.plugin.apList.sideLabelClass = {};
window.plugin.apList.tableColumns = new Array(2);
window.plugin.apList.useCachedPortals = false;
window.plugin.apList.cacheBounds;
window.plugin.apList.cacheActiveZoomLevel;
window.plugin.apList.destroyPortalsGuid = new Array();
window.plugin.apList.portalLocationIndicator;
window.plugin.apList.animTimeout;
// ENTRY POINT ///////////////////////////////////////////////////////////////////
window.plugin.apList.handleUpdate = function() {
if(!requests.isLastRequest('getThinnedEntitiesV4')) return;
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
// CONTENT GENERATION ////////////////////////////////////////////////////////////
// Generate html table from top portals
window.plugin.apList.updatePortalTable = function(side) {
var table = '<table id="ap-list-table">'
+ '<thead>'
+ plugin.apList.tableHeaderBuilder(side)
+ '</thead>';
table += '<tbody>';
var startingPortal = (plugin.apList.currentPage[side] - 1) * plugin.apList.portalPerPage;
for(var i = startingPortal; i < startingPortal + plugin.apList.portalPerPage; i++) {
var portal = plugin.apList.sortedPortals[side][i];
table += plugin.apList.tableRowBuilder(side, portal);
}
table += '</tbody></table>';
$('div#ap-list-table').html(table);
plugin.apList.updatePaginationControl();
plugin.apList.updateStats();
}
window.plugin.apList.tableHeaderBuilder = function(side) {
var headerRow = '<tr>';
$.each(plugin.apList.tableColumns[side], function(ind, column) {
var cssClass = column.headerTooltip ? (column.cssClass + ' help') : column.cssClass;
var title = column.headerTooltip ? column.headerTooltip : '';
var onclick = column.headerOnClick ? column.headerOnClick: '';
var content = column.headerFunction ? column.headerFunction() : column.header;
headerRow += '<td class="' + cssClass + '" '
+ 'title="' + title + '" '
+ 'onclick="' + onclick + '" '
+ '>'
+ content
+ '</td>';
});
headerRow += '</tr>';
return headerRow;
}
window.plugin.apList.tableRowBuilder = function(side,portal) {
var row = "<tr>";
$.each(plugin.apList.tableColumns[side], function(ind, column) {
var content = portal ? column.contentFunction(portal) : '&nbsp;';
row += '<td class="' + column.cssClass + '">'
+ content
+ '</td>';
});
row += '</tr>';
return row;
}
window.plugin.apList.getHeaderCheckbox = function() {
var onClick = 'window.plugin.apList.clearDestroyPortals();';
var content = '<div class="ap-list-checkbox-header" />'
var div = plugin.apList.getCheckbox(onClick, null, content);
return div;
}
window.plugin.apList.getPortalDestroyCheckbox = function(portal) {
// Change background color to border color if portal selected for destroy
var addedClass = plugin.apList.destroyPortalIndex(portal.guid) >= 0
? 'ap-list-checkbox-selected' : '';
var onClick = 'window.plugin.apList.destroyPortal(\'' + portal.guid + '\');';
var div = plugin.apList.getCheckbox(onClick, addedClass, null);
return div;
}
window.plugin.apList.getCheckbox = function(onClick, addedClass, content) {
// 2 div for centering checkbox horizontally and vertically,
// click event on outest div for people with not so good aiming
var div = '<div class="ap-list-checkbox-outer" onclick="' + (onClick || '')+ '">'
+ '<div class="ap-list-checkbox-inner ' + (addedClass || '') + '">'
+ (content || '')
+ '</div>'
+ '</div>';
return div;
}
// Combine ap title and test
window.plugin.apList.getPortalApText = function(portal) {
var title = plugin.apList.getPortalApTitle(portal);
return '<div class="help" title="' + title + '">' + digits(portal.playerApGain.totalAp) + '</div>';
}
// Friendly portal will get resonator upgrade list, enemy
// portal will get ap breakdown
window.plugin.apList.getPortalApTitle = function(portal) {
var t;
var playerApGain = portal.playerApGain;
if(plugin.apList.portalSide(portal) === plugin.apList.SIDE_FRIENDLY) {
t = 'Deploy &amp; Upgrade\n';
for(var i = 0; i < playerApGain.upgradedReso.length; i++) {
var reso = playerApGain.upgradedReso[i];
var apGain = (reso.level === 0) ? DEPLOY_RESONATOR : UPGRADE_ANOTHERS_RESONATOR;
t += 'Resonator on ' + OCTANTS[reso.slot] + '\t' + reso.level + '-&gt;'
+ reso.newLevel + '\t= ' + apGain + '\n';
}
if(playerApGain.captureBonus > 0)
t += 'Capture\t\t= ' + playerApGain.captureBonus + '\n';
if(playerApGain.completionBonus > 0)
t += 'Bonus\t\t= ' + playerApGain.completionBonus + '\n';
t += 'Sum: ' + digits(playerApGain.totalAp) + ' AP';
} else {
t = 'Destroy &amp; 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';
}
return t;
}
window.plugin.apList.getPortalEffectiveLvText = function(portal) {
var title = plugin.apList.getPortalEffectiveLvTitle(portal);
return '<div class="help" title="' + title + '">' + portal.effectiveLevel.effectiveLevel.toFixed(1) + '</div>';
}
window.plugin.apList.getPortalEffectiveLvTitle = function(portal) {
var t = 'Effective energy:\t' + portal.effectiveLevel.effectiveEnergy + '\n'
+ 'Effect of Shields:\t' + portal.effectiveLevel.effectOfShields + '\n'
+ 'Effect of resos dist:\t' + portal.effectiveLevel.effectOfResoDistance + '\n'
+ 'Origin Level:\t' + portal.effectiveLevel.originLevel;
return t;
}
// portal link - single click: select portal
// double click: zoom to and select portal
// hover: show address
window.plugin.apList.getPortalLink = function(portal) {
var latlng = [portal.locationE6.latE6/1E6, portal.locationE6.lngE6/1E6].join();
var jsSingleClick = 'window.plugin.apList.selectPortal(\''+portal.guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+portal.guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.locationE6.latE6
+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+portal.guid;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('<a>',{
"class": 'help',
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
var divClass = plugin.apList.destroyPortalIndex(portal.guid) >= 0
? 'ap-list-link ap-list-link-selected'
: 'ap-list-link';
var div = '<div class="' + divClass + '">'+a+'</div>';
return div;
}
window.plugin.apList.updatePaginationControl = function() {
$('#ap-list-current-p').html(plugin.apList.currentPage[plugin.apList.displaySide]);
$('#ap-list-total-p').html(plugin.apList.totalPage[plugin.apList.displaySide]);
}
window.plugin.apList.updateStats = function() {
var destroyPortals = plugin.apList.destroyPortalsGuid.length;
if(destroyPortals === 0) {
title = 'Stats';
} else {
var destroyAP = 0;
var averageEL = 0;
$.each(plugin.apList.destroyPortalsGuid, function(ind,guid) {
destroyAP += plugin.apList.cachedPortals[guid].playerApGain.totalAp;
averageEL += plugin.apList.cachedPortals[guid].effectiveLevel.effectiveLevel;
});
averageEL = Math.round(averageEL / destroyPortals * 10) / 10;
var title = 'Stats\n'
+ 'Selected portal(s)\t=\t' + destroyPortals + '\n'
+ 'Total AP\t=\t' + destroyAP + '\n'
+ 'Average EL\t=\t' + averageEL;
}
$('#ap-list-misc-info').attr('title', title);
}
// MAIN LOGIC FUNCTIONS //////////////////////////////////////////////////////////
// Loop through portals and get playerApGain, then put in sortedPortals by side and sort them by AP.
window.plugin.apList.updateSortedPortals = function() {
plugin.apList.sortedPortals[plugin.apList.SIDE_FRIENDLY] = new Array();
plugin.apList.sortedPortals[plugin.apList.SIDE_ENEMY] = new Array();
// Make a backup of cachedPortals with shallow copy
// If cache is not enabled, empty cachedPortals. In following
// "$.each" loop, the backup portal will copy back into
// cachedPortals if it exist in "window.portals"" and didn't change.'
var oldcachedPortal = $.extend({},plugin.apList.cachedPortals);
if(!plugin.apList.useCachedPortals)
plugin.apList.cachedPortals = {};
$.each(window.portals, function(key, value) {
var portal = value.options.details;
var cachedPortal = oldcachedPortal[key];
// If portal is changed, update playerApGain with latest
// information
if(!cachedPortal
|| value.timestamp !== cachedPortal.timestamp
|| plugin.apList.isFieldsChanged(portal.portalV2.linkedFields, cachedPortal.portalV2.linkedFields)) {
// Shallow copy portal detail to cachedPortal
cachedPortal = $.extend({}, portal);
var side = plugin.apList.portalSide(portal);
var getApGainFunc = plugin.apList.playerApGainFunc[side];
// Assign playerApGain and guid to cachedPortal
cachedPortal.timestamp = value.timestamp
cachedPortal.playerApGain = getApGainFunc(portal);
cachedPortal.effectiveLevel = plugin.apList.getEffectiveLevel(portal);
cachedPortal.guid = value.options.guid;
}
plugin.apList.cachedPortals[key] = cachedPortal;
});
// Add all portals to sortedPortals by side and sort sortedPortals by AP
$.each(plugin.apList.cachedPortals, function(key, portal) {
var side = plugin.apList.portalSide(portal);
plugin.apList.sortedPortals[side].push(portal);
});
$.each(plugin.apList.sides, function(ind, side) {
plugin.apList.sortedPortals[side].sort(plugin.apList.comparePortal);
});
// Modify sortedPortals if any portal selected for destroy
plugin.apList.handleDestroyPortal();
// Update pagination control data
plugin.apList.updateTotalPages();
}
// 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() {
if(plugin.apList.destroyPortalsGuid.length === 0) return;
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 with deep copy 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(plugin.apList.comparePortal);
}
window.plugin.apList.updateTotalPages = function() {
$.each(plugin.apList.sortedPortals, function(side, portals) {
plugin.apList.totalPage[side] = Math.max(Math.ceil(portals.length / plugin.apList.portalPerPage), 1);
plugin.apList.currentPage[side] = Math.min(plugin.apList.totalPage[side], plugin.apList.currentPage[side]);
});
}
window.plugin.apList.isFieldsChanged = function(a,b) {
// http://stackoverflow.com/questions/1773069/using-jquery-to-compare-two-arrays
return $(a).not(b).get().length === 0 && $(b).not(a).get().length === 0;;
}
window.plugin.apList.portalSide = function(portal) {
return (portal.controllingTeam.team === PLAYER.team
|| portal.controllingTeam.team === 'NEUTRAL')
? plugin.apList.SIDE_FRIENDLY
: plugin.apList.SIDE_ENEMY;
}
// Get AP of friendly portal
window.plugin.apList.getDeployOrUpgradeApGain = function(d) {
var playerResoCount = new Array(MAX_PORTAL_LEVEL + 1);
var otherReso = new Array();
var totalAp = 0;
var upgradedReso = new Array();
var deployCount = 0;
var upgradedCount = 0;
var captureBonus = 0;
var completionBonus = 0;
// loop through reso slot and find empty reso, deployed
// by others(only level lower than player level) or by player.
for(var i = 0; i < 8; i++) {
var reso = d.resonatorArray.resonators[i];
// Empty reso
if(!reso) {
otherReso.push({slot: i, level: 0});
continue;
}
// By player
if(reso.ownerGuid === window.PLAYER.guid) {
playerResoCount[reso.level] = (playerResoCount[reso.level] || 0) + 1;
continue;
}
// By others and level lower than player
if(reso.level < window.PLAYER.level) {
otherReso.push(reso);
}
}
// Sort others reso low to high, last reso in otherReso get upgrade first.
otherReso.sort(function(a, b) {return a.level - b.level;});
// Find out available count of reso for each level
for(var i = window.PLAYER.level; i > 0 && otherReso.length > 0; i--) {
var availableCount = MAX_RESO_PER_PLAYER[i] - (playerResoCount[i] || 0);
// Loop through lower level reso of others and add to result
while(availableCount > 0 && otherReso.length > 0) {
var targetReso = otherReso.pop();
// Can only upgrade lower level reso
if(targetReso.level >= i)
continue;
// Add upgraded reso to result
targetReso.newLevel = i;
upgradedReso.push(targetReso);
// Counting upgrade or deploy
(targetReso.level === 0) ? deployCount++ : upgradedCount++;
availableCount--;
}
}
if(deployCount > 0) completionBonus = COMPLETION_BONUS;
if(deployCount === 8) captureBonus = CAPTURE_PORTAL;
totalAp = deployCount * DEPLOY_RESONATOR
+ upgradedCount * UPGRADE_ANOTHERS_RESONATOR
+ captureBonus
+ completionBonus;
return {
captureBonus: captureBonus,
completionBonus: completionBonus,
totalAp: totalAp,
upgradedReso: upgradedReso
};
}
window.plugin.apList.getAttackApGain = function(d) {
var resoCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if (!reso)
return true;
resoCount += 1;
});
var linkCount = d.portalV2.linkedEdges ? d.portalV2.linkedEdges.length : 0;
var fieldCount = d.portalV2.linkedFields ? d.portalV2.linkedFields.length : 0;
var resoAp = resoCount * DESTROY_RESONATOR;
var linkAp = linkCount * DESTROY_LINK;
var fieldAp = fieldCount * DESTROY_FIELD;
var destroyAp = resoAp + linkAp + fieldAp;
var captureAp = CAPTURE_PORTAL + 8 * DEPLOY_RESONATOR + COMPLETION_BONUS;
var totalAp = destroyAp + captureAp;
return {
totalAp: totalAp,
destroyAp: destroyAp,
captureAp: captureAp,
resoCount: resoCount,
linkCount: linkCount,
fieldCount: fieldCount
}
}
window.plugin.apList.getEffectiveLevel = function(portal) {
var effectiveEnergy = 0;
var effectiveLevel = 0;
var resosStats = plugin.apList.getResonatorsStats(portal);
// Calculate effective energy
var effectOfShields = plugin.apList.getShieldsEffect(portal);
// If avgResoDistance is 0, 8 resonators in the same place and can be treated as 1 resonator.
// So the minimum effect of resonator distance is 1/8
var effectOfResoDistance = (1 + (resosStats.avgResoDistance / HACK_RANGE) * 7 ) / 8;
effectiveEnergy = resosStats.currentEnergy * effectOfShields * effectOfResoDistance;
// Calculate effective level
for(var i = MAX_PORTAL_LEVEL; i >= 0; i--) {
var baseLevel = i;
var baseLevelEnergy = RESO_NRG[baseLevel] * 8;
if(effectiveEnergy >= baseLevelEnergy) {
var energyToNextLevel = baseLevel === MAX_PORTAL_LEVEL
? baseLevelEnergy - RESO_NRG[MAX_PORTAL_LEVEL - 1] * 8 // Extrapolate
: RESO_NRG[baseLevel + 1] * 8 - baseLevelEnergy; // Interpolate
var additionalLevel = (effectiveEnergy - baseLevelEnergy) / energyToNextLevel;
effectiveLevel = baseLevel + additionalLevel;
break;
}
}
// Account for damage do to player by portal
var portalLevel = parseInt(getPortalLevel(portal));
if(effectiveLevel < portalLevel) {
var energyPect = resosStats.currentEnergy / resosStats.totalEnergy;
effectiveLevel = effectiveLevel * (1-energyPect) + portalLevel * energyPect;
}
return {
effectiveLevel: Math.round(effectiveLevel * 10) / 10,
effectiveEnergy: parseInt(effectiveEnergy),
effectOfShields: Math.round(effectOfShields * 100) / 100,
effectOfResoDistance: Math.round(effectOfResoDistance * 100) / 100,
originLevel: portalLevel
};
}
window.plugin.apList.getResonatorsStats = function(portal) {
var totalEnergy = 0;
var currentEnergy = 0;
var avgResoDistance = 0;
$.each(portal.resonatorArray.resonators, function(ind, reso) {
if (!reso)
return true;
totalEnergy += RESO_NRG[reso.level];
currentEnergy += reso.energyTotal;
avgResoDistance += (reso.distanceToPortal / 8);
});
return {
totalEnergy: totalEnergy,
currentEnergy: currentEnergy,
avgResoDistance: avgResoDistance};
}
window.plugin.apList.getShieldsEffect = function(portal) {
// shield effect: each shield's mitigation value is assumed to be the percentage of the damage it will absorb
// the rest of the damage gets through to the next shield, and so on.
// so, to calculate the total protection, we multiply the fractions of damage allowed through each shield
// to get a final figure of how much damage gets through
// e.g.
// one shield: mitigation 10 - lets 90% of the damage through
// two shields: mitigation 20 and 30 - first one lets 80% through, second 70% of the remaining
// so final amount let through = 0.8 * 0.7 = 0.56 = 56% damage let through
// four shields: mitigation 30 - 70% through each = 0.7 * 0.7 * 0.7 * 0.7 = 0.24 = 24% damage gets through all four
var shieldsEffect = 1;
$.each(portal.portalV2.linkedModArray, function(ind, mod) {
if(!mod)
return true;
if(!mod.stats.MITIGATION)
return true;
shieldsEffect *= (1 - parseInt(mod.stats.MITIGATION)/100.0);
});
return shieldsEffect;
}
// For using in .sort(func) of sortedPortals
// Use options in plugin.apList.sortOptions. Each type of sortBy has
// array of options. Option consist of an ordering and a property chain.
//
// Sorting done by loop through the options, get the property by
// property chain of each option, compare the property of two object
// with the ordering of option and return the result when the first
// difference is found.
window.plugin.apList.comparePortal = function(a,b) {
var result = 0;
var options = plugin.apList.sortOptions[plugin.apList.sortBy];
$.each(options, function(indO, option) {
var aProperty = a;
var bProperty = b;
// Walking down the chain
$.each(option.chain, function(indPN, propertyName) {
aProperty = aProperty[propertyName];
bProperty = bProperty[propertyName];
});
// compare next property if equal
if(aProperty === bProperty) return true;
result = (aProperty > bProperty ? 1 : -1) * option.order;
return false;
});
return result;
}
// FEATURE TOGGLES AND INTERACTION HANDLER ///////////////////////////////////////
window.plugin.apList.enableCache = function() {
plugin.apList.useCachedPortals = true;
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
window.plugin.apList.disableCache = function() {
plugin.apList.useCachedPortals = false;
plugin.apList.cachedPortals = {};
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
window.plugin.apList.selectPortal = function(guid) {
// Add error catching to avoid following link of portal if error
// occurred in renderPortalDetails or hooked plugin
try {
renderPortalDetails(guid);
} catch(e) {
console.error(e.message);
console.log(e.stack);
console.log('Skipping error in renderPortalDetails or hooked plugin')
}
plugin.apList.setPortalLocationIndicator(guid);
}
window.plugin.apList.setPortalLocationIndicator = function(guid) {
var portal = window.portals[guid];
if(!portal) return;
var startRadius = screen.availWidth / 2;
var portalRadius = portal.options.radius;
var latlng = portal.getLatLng();
var property = {
radius: startRadius,
fill: false,
color: COLOR_SELECTED_PORTAL,
weight: 2,
opacity: 1,
portalRadius: portalRadius,
clickable: false };
if(plugin.apList.portalLocationIndicator)
map.removeLayer(plugin.apList.portalLocationIndicator);
if(plugin.apList.animTimeout)
clearTimeout(plugin.apList.animTimeout);
plugin.apList.portalLocationIndicator = L.circleMarker(latlng, property).addTo(map);
plugin.apList.animTimeout = setTimeout(plugin.apList.animPortalLocationIndicator,100);
}
window.plugin.apList.animPortalLocationIndicator = function() {
var radius = plugin.apList.portalLocationIndicator.options.radius;
var portalRadius = plugin.apList.portalLocationIndicator.options.portalRadius
if(radius > portalRadius) {
var step = radius / 3;
if(radius < 80) step = step / 3;
var newRadius = plugin.apList.portalLocationIndicator.options.radius -= step;
plugin.apList.portalLocationIndicator.setRadius(newRadius);
if(plugin.apList.animTimeout)
clearTimeout(plugin.apList.animTimeout);
plugin.apList.animTimeout = setTimeout(plugin.apList.animPortalLocationIndicator,100);
} else {
map.removeLayer(plugin.apList.portalLocationIndicator);
}
}
window.plugin.apList.changePage = function(step, toEnd) {
var side = plugin.apList.displaySide;
var oldPage = plugin.apList.currentPage[side];
if(toEnd) {
if(step < 0) plugin.apList.currentPage[side] = 1;
if(step > 0) plugin.apList.currentPage[side] = plugin.apList.totalPage[side]
} else {
plugin.apList.currentPage[side] += step;
if(plugin.apList.currentPage[side] < 1)
plugin.apList.currentPage[side] = 1;
if(plugin.apList.currentPage[side] > plugin.apList.totalPage[side])
plugin.apList.currentPage[side] = plugin.apList.totalPage[side];
}
if(plugin.apList.currentPage[side] !== oldPage)
plugin.apList.updatePortalTable(side);
}
window.plugin.apList.changeSorting = function(sortBy) {
var oldSortBy = plugin.apList.sortBy;
plugin.apList.sortBy = sortBy;
if(plugin.apList.sortBy !== oldSortBy) {
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
}
window.plugin.apList.clearDestroyPortals = function() {
plugin.apList.destroyPortalsGuid = new Array();
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
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);
}
// Change display table to friendly portals
window.plugin.apList.displayFriendly = function() {
plugin.apList.changeDisplaySide(plugin.apList.SIDE_FRIENDLY);
}
// Change display table to enemy portals
window.plugin.apList.displayEnemy = function() {
plugin.apList.changeDisplaySide(plugin.apList.SIDE_ENEMY);
}
window.plugin.apList.changeDisplaySide = function(side) {
var isChange = (plugin.apList.displaySide !== side);
var scrollTo = 0;
if(isChange) {
plugin.apList.displaySide = side;
plugin.apList.updatePortalTable(side);
plugin.apList.toggleSideLabel(side);
scrollTo = $("#ap-list").position().top + $("#ap-list").outerHeight()
- $("#sidebar").height() + $("#sidebar").scrollTop();
}
$('#sidebar').scrollTop(scrollTo);
}
window.plugin.apList.toggleSideLabel = function(side) {
$.each(plugin.apList.sides, function(ind,key) {
var labelClass = plugin.apList.sideLabelClass[key];
var opacity = (key === side) ? 1.0 : 0.5;
$(labelClass).css("opacity", opacity);
});
}
window.plugin.apList.hideReloadLabel = function() {
$('#ap-list-reload').hide();
}
window.plugin.apList.showReloadLabel = function() {
$('#ap-list-reload').show();
}
// SETUP /////////////////////////////////////////////////////////////////////////
window.plugin.apList.setupVar = function() {
plugin.apList.sides[plugin.apList.SIDE_FRIENDLY] = plugin.apList.SIDE_FRIENDLY;
plugin.apList.sides[plugin.apList.SIDE_ENEMY] = plugin.apList.SIDE_ENEMY;
plugin.apList.playerApGainFunc[plugin.apList.SIDE_FRIENDLY]
= plugin.apList.getDeployOrUpgradeApGain;
plugin.apList.playerApGainFunc[plugin.apList.SIDE_ENEMY]
= plugin.apList.getAttackApGain;
plugin.apList.sideLabelClass[plugin.apList.SIDE_FRIENDLY]
= "#ap-list-frd";
plugin.apList.sideLabelClass[plugin.apList.SIDE_ENEMY]
= "#ap-list-eny";
plugin.apList.sortedPortals[plugin.apList.SIDE_FRIENDLY] = new Array();
plugin.apList.sortedPortals[plugin.apList.SIDE_ENEMY] = new Array();
}
window.plugin.apList.setupSorting = function() {
var optionELAsc = {
order: plugin.apList.SORT_ASC,
chain: ['effectiveLevel','effectiveLevel']};
var optionAPDesc = {
order: plugin.apList.SORT_DESC,
chain: ['playerApGain','totalAp']};
var optionGuidDesc = {
order: plugin.apList.SORT_DESC,
chain: ['guid']};
// order by EL -> AP -> guid
plugin.apList.sortOptions[plugin.apList.SORT_BY_EL] = [optionELAsc, optionAPDesc, optionGuidDesc];
// order by AP -> EL -> guid
plugin.apList.sortOptions[plugin.apList.SORT_BY_AP] = [optionAPDesc, optionELAsc, optionGuidDesc];
}
// Setup table columns for header builder and row builder
window.plugin.apList.setupTableColumns = function() {
var enemyColumns = new Array();
var friendlyColumns = new Array();
// AP and Eff. LV columns are same in enemy and friendly table
var apColumn = {
header: 'AP',
headerOnClick: 'plugin.apList.changeSorting(plugin.apList.SORT_BY_AP);',
headerTooltip: 'Click to sort by AP',
cssClass: 'ap-list-td-ap',
contentFunction: plugin.apList.getPortalApText
};
var effectiveLevelColumn = {
header: 'EL',
headerOnClick: 'plugin.apList.changeSorting(plugin.apList.SORT_BY_EL);',
headerTooltip: 'Effective Level\nClick to sort by EL',
cssClass: 'ap-list-td-eff-lv',
contentFunction: plugin.apList.getPortalEffectiveLvText
};
// Columns: Checkbox | Portal | AP | Eff. LV
enemyColumns.push({
headerFunction: plugin.apList.getHeaderCheckbox,
headerTooltip: 'Unselect all',
cssClass: 'ap-list-td-checkbox',
contentFunction: plugin.apList.getPortalDestroyCheckbox
});
enemyColumns.push({
header: 'Portal',
cssClass: 'ap-list-td-link ap-list-td-link-eny',
contentFunction: plugin.apList.getPortalLink
});
enemyColumns.push(apColumn);
enemyColumns.push(effectiveLevelColumn);
// Columns: Portal | AP | Eff. LV
friendlyColumns.push({
header: 'Portal',
cssClass: 'ap-list-td-link ap-list-td-link-frd',
contentFunction: plugin.apList.getPortalLink
});
friendlyColumns.push(apColumn);
friendlyColumns.push(effectiveLevelColumn);
plugin.apList.tableColumns[plugin.apList.SIDE_ENEMY] = enemyColumns;
plugin.apList.tableColumns[plugin.apList.SIDE_FRIENDLY] = friendlyColumns;
}
window.plugin.apList.setupCSS = function() {
$("<style>")
.prop("type", "text/css")
.html("@@INCLUDESTRING:plugins/ap-list.css@@")
.appendTo("head");
}
window.plugin.apList.setupList = function() {
var content = '<div id="ap-list">'
+ '<span id="ap-list-side-labels">'
+ '<span id="ap-list-eny">'
+ '<a href="#" onclick="window.plugin.apList.displayEnemy();return false;">Enemy</a>'
+ '</span>'
+ '<span id="ap-list-frd">'
+ '<a href="#" onclick="window.plugin.apList.displayFriendly();return false;">Friendly</a>'
+ '</span>'
+ '</span>'
+ '<span id="ap-list-reload">'
+ '<a href="#" title="Clear list and reload" onclick="window.plugin.apList.disableCache();'
+ 'plugin.apList.hideReloadLabel();return false;">↻ R</a>'
+ '</span>'
+ '<div id="ap-list-table"></div>'
+ '<span id="ap-list-misc-info" title="Stats">...</span>'
+ '<span id="ap-list-pagination"></span>'
+ '</div>';
$('#sidebar').append(content);
$('#ap-list-reload').hide();
}
window.plugin.apList.setupPagination = function() {
var content = '<div class="ap-list-center-div">'
+ '<div id="ap-list-first-p" class="ap-list-page-control" onclick="plugin.apList.changePage(-1, true);">'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-half"/>'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-half"/>'
+ '</div>'
+ '<div id="ap-list-next-p" class="ap-list-page-control" onclick="plugin.apList.changePage(-1);">'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-full"/>'
+ '</div>'
+ '<div id="ap-list-current-p" class="ap-list-page-text">1</div>'
+ '<div id="ap-list-page-slash" class="ap-list-page-text">/</div>'
+ '<div id="ap-list-total-p" class="ap-list-page-text">1</div>'
+ '<div id="ap-list-prev-p" class="ap-list-page-control" onclick="plugin.apList.changePage(1);">'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-full"/>'
+ '</div>'
+ '<div id="ap-list-last-p" class="ap-list-page-control" onclick="plugin.apList.changePage(1, true);">'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-half"/>'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-half"/>'
+ '</div>'
+ '<div class="spacer" style="clear: both;"></div>'// fix collapsion of parent caused by inner div's float:left
+ '</div>';
$('#ap-list-pagination').html(content);
}
window.plugin.apList.setupMapEvent = function() {
map.on('zoomstart', function() {
plugin.apList.setupMapEvent.zoomLevelBefore = map.getZoom();
// Stop changing cacheBounds if cache enabled
if(!plugin.apList.useCachedPortals)
plugin.apList.cacheBounds = map.getBounds();
});
map.on('zoomend', function() {
// if zooming in and cache not yet enable, enable it
if(!plugin.apList.useCachedPortals
&& map.getZoom() > plugin.apList.setupMapEvent.zoomLevelBefore) {
plugin.apList.enableCache();
plugin.apList.showReloadLabel();
}
});
map.on('moveend zoomend', function() {
// disable cache after out of cache bounds
if(plugin.apList.useCachedPortals) {
var currentBounds = map.getBounds();
if(!plugin.apList.cacheBounds.contains(currentBounds)) {
plugin.apList.disableCache();
plugin.apList.hideReloadLabel();
}
}
});
}
var setup = function() {
window.plugin.apList.setupVar();
window.plugin.apList.setupSorting();
window.plugin.apList.setupTableColumns();
window.plugin.apList.setupCSS();
window.plugin.apList.setupList();
window.plugin.apList.setupPagination();
window.plugin.apList.setupMapEvent();
window.addHook('mapDataRefreshEnd', window.plugin.apList.handleUpdate);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-bookmarks@ZasoGD
// @name IITC plugin: Bookmarks for maps and portals
// @category Controls
// @version 0.2.6.@@DATETIMEVERSION@@
// @version 0.2.7.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -335,10 +335,11 @@
// If portal isn't saved in bookmarks: Add this bookmark
else{
// Get portal name and coordinates
var d = window.portals[guid].options.details;
var label = d.portalV2.descriptiveText.TITLE;
var lat = (d.locationE6.latE6)/1E6;
var lng = (d.locationE6.lngE6)/1E6;
var p = window.portals[guid];
var d = p.options.data;
var label = d.title;
var lat = p.getLatLng().lat;
var lng = p.getLatLng().lng;
var latlng = lat+','+lng;
var ID = window.plugin.bookmarks.generateID();

View File

@ -0,0 +1,942 @@
// ==UserScript==
// @id iitc-plugin-ap-list@xelio
// @name IITC plugin: AP List
// @category Info
// @version 0.5.7.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] List portals by AP of either faction or by effective level. Other functions and controls please refer to the Userguide.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.apList = function() {
};
window.plugin.apList.cachedPortals = {};
window.plugin.apList.SIDE_FRIENDLY = 0;
window.plugin.apList.SIDE_ENEMY = 1;
window.plugin.apList.displaySide = window.plugin.apList.SIDE_ENEMY;
window.plugin.apList.sides = new Array(2);
window.plugin.apList.sortedPortals = new Array(2);
window.plugin.apList.playerApGainFunc = new Array(2);
window.plugin.apList.SORT_BY_AP = 'AP';
window.plugin.apList.SORT_BY_EL = 'EL';
window.plugin.apList.sortBy = window.plugin.apList.SORT_BY_AP;
window.plugin.apList.SORT_ASC = 1;
window.plugin.apList.SORT_DESC = -1;
window.plugin.apList.sortOptions = {};
window.plugin.apList.currentPage = [1,1];
window.plugin.apList.totalPage = [1,1];
window.plugin.apList.portalPerPage = 10;
window.plugin.apList.sideLabelClass = {};
window.plugin.apList.tableColumns = new Array(2);
window.plugin.apList.useCachedPortals = false;
window.plugin.apList.cacheBounds;
window.plugin.apList.cacheActiveZoomLevel;
window.plugin.apList.destroyPortalsGuid = new Array();
window.plugin.apList.portalLocationIndicator;
window.plugin.apList.animTimeout;
// ENTRY POINT ///////////////////////////////////////////////////////////////////
window.plugin.apList.handleUpdate = function() {
if(!requests.isLastRequest('getThinnedEntitiesV4')) return;
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
// CONTENT GENERATION ////////////////////////////////////////////////////////////
// Generate html table from top portals
window.plugin.apList.updatePortalTable = function(side) {
var table = '<table id="ap-list-table">'
+ '<thead>'
+ plugin.apList.tableHeaderBuilder(side)
+ '</thead>';
table += '<tbody>';
var startingPortal = (plugin.apList.currentPage[side] - 1) * plugin.apList.portalPerPage;
for(var i = startingPortal; i < startingPortal + plugin.apList.portalPerPage; i++) {
var portal = plugin.apList.sortedPortals[side][i];
table += plugin.apList.tableRowBuilder(side, portal);
}
table += '</tbody></table>';
$('div#ap-list-table').html(table);
plugin.apList.updatePaginationControl();
plugin.apList.updateStats();
}
window.plugin.apList.tableHeaderBuilder = function(side) {
var headerRow = '<tr>';
$.each(plugin.apList.tableColumns[side], function(ind, column) {
var cssClass = column.headerTooltip ? (column.cssClass + ' help') : column.cssClass;
var title = column.headerTooltip ? column.headerTooltip : '';
var onclick = column.headerOnClick ? column.headerOnClick: '';
var content = column.headerFunction ? column.headerFunction() : column.header;
headerRow += '<td class="' + cssClass + '" '
+ 'title="' + title + '" '
+ 'onclick="' + onclick + '" '
+ '>'
+ content
+ '</td>';
});
headerRow += '</tr>';
return headerRow;
}
window.plugin.apList.tableRowBuilder = function(side,portal) {
var row = "<tr>";
$.each(plugin.apList.tableColumns[side], function(ind, column) {
var content = portal ? column.contentFunction(portal) : '&nbsp;';
row += '<td class="' + column.cssClass + '">'
+ content
+ '</td>';
});
row += '</tr>';
return row;
}
window.plugin.apList.getHeaderCheckbox = function() {
var onClick = 'window.plugin.apList.clearDestroyPortals();';
var content = '<div class="ap-list-checkbox-header" />'
var div = plugin.apList.getCheckbox(onClick, null, content);
return div;
}
window.plugin.apList.getPortalDestroyCheckbox = function(portal) {
// Change background color to border color if portal selected for destroy
var addedClass = plugin.apList.destroyPortalIndex(portal.guid) >= 0
? 'ap-list-checkbox-selected' : '';
var onClick = 'window.plugin.apList.destroyPortal(\'' + portal.guid + '\');';
var div = plugin.apList.getCheckbox(onClick, addedClass, null);
return div;
}
window.plugin.apList.getCheckbox = function(onClick, addedClass, content) {
// 2 div for centering checkbox horizontally and vertically,
// click event on outest div for people with not so good aiming
var div = '<div class="ap-list-checkbox-outer" onclick="' + (onClick || '')+ '">'
+ '<div class="ap-list-checkbox-inner ' + (addedClass || '') + '">'
+ (content || '')
+ '</div>'
+ '</div>';
return div;
}
// Combine ap title and test
window.plugin.apList.getPortalApText = function(portal) {
var title = plugin.apList.getPortalApTitle(portal);
return '<div class="help" title="' + title + '">' + digits(portal.playerApGain.totalAp) + '</div>';
}
// Friendly portal will get resonator upgrade list, enemy
// portal will get ap breakdown
window.plugin.apList.getPortalApTitle = function(portal) {
var t;
var playerApGain = portal.playerApGain;
if(plugin.apList.portalSide(portal) === plugin.apList.SIDE_FRIENDLY) {
t = 'Deploy &amp; Upgrade\n';
for(var i = 0; i < playerApGain.upgradedReso.length; i++) {
var reso = playerApGain.upgradedReso[i];
var apGain = (reso.level === 0) ? DEPLOY_RESONATOR : UPGRADE_ANOTHERS_RESONATOR;
t += 'Resonator on ' + OCTANTS[reso.slot] + '\t' + reso.level + '-&gt;'
+ reso.newLevel + '\t= ' + apGain + '\n';
}
if(playerApGain.captureBonus > 0)
t += 'Capture\t\t= ' + playerApGain.captureBonus + '\n';
if(playerApGain.completionBonus > 0)
t += 'Bonus\t\t= ' + playerApGain.completionBonus + '\n';
t += 'Sum: ' + digits(playerApGain.totalAp) + ' AP';
} else {
t = 'Destroy &amp; 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';
}
return t;
}
window.plugin.apList.getPortalEffectiveLvText = function(portal) {
var title = plugin.apList.getPortalEffectiveLvTitle(portal);
return '<div class="help" title="' + title + '">' + portal.effectiveLevel.effectiveLevel.toFixed(1) + '</div>';
}
window.plugin.apList.getPortalEffectiveLvTitle = function(portal) {
var t = 'Effective energy:\t' + portal.effectiveLevel.effectiveEnergy + '\n'
+ 'Effect of Shields:\t' + portal.effectiveLevel.effectOfShields + '\n'
+ 'Effect of resos dist:\t' + portal.effectiveLevel.effectOfResoDistance + '\n'
+ 'Origin Level:\t' + portal.effectiveLevel.originLevel;
return t;
}
// portal link - single click: select portal
// double click: zoom to and select portal
// hover: show address
window.plugin.apList.getPortalLink = function(portal) {
var latlng = [portal.locationE6.latE6/1E6, portal.locationE6.lngE6/1E6].join();
var jsSingleClick = 'window.plugin.apList.selectPortal(\''+portal.guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+portal.guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.locationE6.latE6
+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+portal.guid;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('<a>',{
"class": 'help',
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
var divClass = plugin.apList.destroyPortalIndex(portal.guid) >= 0
? 'ap-list-link ap-list-link-selected'
: 'ap-list-link';
var div = '<div class="' + divClass + '">'+a+'</div>';
return div;
}
window.plugin.apList.updatePaginationControl = function() {
$('#ap-list-current-p').html(plugin.apList.currentPage[plugin.apList.displaySide]);
$('#ap-list-total-p').html(plugin.apList.totalPage[plugin.apList.displaySide]);
}
window.plugin.apList.updateStats = function() {
var destroyPortals = plugin.apList.destroyPortalsGuid.length;
if(destroyPortals === 0) {
title = 'Stats';
} else {
var destroyAP = 0;
var averageEL = 0;
$.each(plugin.apList.destroyPortalsGuid, function(ind,guid) {
destroyAP += plugin.apList.cachedPortals[guid].playerApGain.totalAp;
averageEL += plugin.apList.cachedPortals[guid].effectiveLevel.effectiveLevel;
});
averageEL = Math.round(averageEL / destroyPortals * 10) / 10;
var title = 'Stats\n'
+ 'Selected portal(s)\t=\t' + destroyPortals + '\n'
+ 'Total AP\t=\t' + destroyAP + '\n'
+ 'Average EL\t=\t' + averageEL;
}
$('#ap-list-misc-info').attr('title', title);
}
// MAIN LOGIC FUNCTIONS //////////////////////////////////////////////////////////
// Loop through portals and get playerApGain, then put in sortedPortals by side and sort them by AP.
window.plugin.apList.updateSortedPortals = function() {
plugin.apList.sortedPortals[plugin.apList.SIDE_FRIENDLY] = new Array();
plugin.apList.sortedPortals[plugin.apList.SIDE_ENEMY] = new Array();
// Make a backup of cachedPortals with shallow copy
// If cache is not enabled, empty cachedPortals. In following
// "$.each" loop, the backup portal will copy back into
// cachedPortals if it exist in "window.portals"" and didn't change.'
var oldcachedPortal = $.extend({},plugin.apList.cachedPortals);
if(!plugin.apList.useCachedPortals)
plugin.apList.cachedPortals = {};
$.each(window.portals, function(key, value) {
var portal = value.options.details;
var cachedPortal = oldcachedPortal[key];
// If portal is changed, update playerApGain with latest
// information
if(!cachedPortal
|| value.timestamp !== cachedPortal.timestamp
|| plugin.apList.isFieldsChanged(portal.portalV2.linkedFields, cachedPortal.portalV2.linkedFields)) {
// Shallow copy portal detail to cachedPortal
cachedPortal = $.extend({}, portal);
var side = plugin.apList.portalSide(portal);
var getApGainFunc = plugin.apList.playerApGainFunc[side];
// Assign playerApGain and guid to cachedPortal
cachedPortal.timestamp = value.timestamp
cachedPortal.playerApGain = getApGainFunc(portal);
cachedPortal.effectiveLevel = plugin.apList.getEffectiveLevel(portal);
cachedPortal.guid = value.options.guid;
}
plugin.apList.cachedPortals[key] = cachedPortal;
});
// Add all portals to sortedPortals by side and sort sortedPortals by AP
$.each(plugin.apList.cachedPortals, function(key, portal) {
var side = plugin.apList.portalSide(portal);
plugin.apList.sortedPortals[side].push(portal);
});
$.each(plugin.apList.sides, function(ind, side) {
plugin.apList.sortedPortals[side].sort(plugin.apList.comparePortal);
});
// Modify sortedPortals if any portal selected for destroy
plugin.apList.handleDestroyPortal();
// Update pagination control data
plugin.apList.updateTotalPages();
}
// 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() {
if(plugin.apList.destroyPortalsGuid.length === 0) return;
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 with deep copy 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(plugin.apList.comparePortal);
}
window.plugin.apList.updateTotalPages = function() {
$.each(plugin.apList.sortedPortals, function(side, portals) {
plugin.apList.totalPage[side] = Math.max(Math.ceil(portals.length / plugin.apList.portalPerPage), 1);
plugin.apList.currentPage[side] = Math.min(plugin.apList.totalPage[side], plugin.apList.currentPage[side]);
});
}
window.plugin.apList.isFieldsChanged = function(a,b) {
// http://stackoverflow.com/questions/1773069/using-jquery-to-compare-two-arrays
return $(a).not(b).get().length === 0 && $(b).not(a).get().length === 0;;
}
window.plugin.apList.portalSide = function(portal) {
return (portal.controllingTeam.team === PLAYER.team
|| portal.controllingTeam.team === 'NEUTRAL')
? plugin.apList.SIDE_FRIENDLY
: plugin.apList.SIDE_ENEMY;
}
// Get AP of friendly portal
window.plugin.apList.getDeployOrUpgradeApGain = function(d) {
var playerResoCount = new Array(MAX_PORTAL_LEVEL + 1);
var otherReso = new Array();
var totalAp = 0;
var upgradedReso = new Array();
var deployCount = 0;
var upgradedCount = 0;
var captureBonus = 0;
var completionBonus = 0;
// loop through reso slot and find empty reso, deployed
// by others(only level lower than player level) or by player.
for(var i = 0; i < 8; i++) {
var reso = d.resonatorArray.resonators[i];
// Empty reso
if(!reso) {
otherReso.push({slot: i, level: 0});
continue;
}
// By player
if(reso.ownerGuid === window.PLAYER.guid) {
playerResoCount[reso.level] = (playerResoCount[reso.level] || 0) + 1;
continue;
}
// By others and level lower than player
if(reso.level < window.PLAYER.level) {
otherReso.push(reso);
}
}
// Sort others reso low to high, last reso in otherReso get upgrade first.
otherReso.sort(function(a, b) {return a.level - b.level;});
// Find out available count of reso for each level
for(var i = window.PLAYER.level; i > 0 && otherReso.length > 0; i--) {
var availableCount = MAX_RESO_PER_PLAYER[i] - (playerResoCount[i] || 0);
// Loop through lower level reso of others and add to result
while(availableCount > 0 && otherReso.length > 0) {
var targetReso = otherReso.pop();
// Can only upgrade lower level reso
if(targetReso.level >= i)
continue;
// Add upgraded reso to result
targetReso.newLevel = i;
upgradedReso.push(targetReso);
// Counting upgrade or deploy
(targetReso.level === 0) ? deployCount++ : upgradedCount++;
availableCount--;
}
}
if(deployCount > 0) completionBonus = COMPLETION_BONUS;
if(deployCount === 8) captureBonus = CAPTURE_PORTAL;
totalAp = deployCount * DEPLOY_RESONATOR
+ upgradedCount * UPGRADE_ANOTHERS_RESONATOR
+ captureBonus
+ completionBonus;
return {
captureBonus: captureBonus,
completionBonus: completionBonus,
totalAp: totalAp,
upgradedReso: upgradedReso
};
}
window.plugin.apList.getAttackApGain = function(d) {
var resoCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if (!reso)
return true;
resoCount += 1;
});
var linkCount = d.portalV2.linkedEdges ? d.portalV2.linkedEdges.length : 0;
var fieldCount = d.portalV2.linkedFields ? d.portalV2.linkedFields.length : 0;
var resoAp = resoCount * DESTROY_RESONATOR;
var linkAp = linkCount * DESTROY_LINK;
var fieldAp = fieldCount * DESTROY_FIELD;
var destroyAp = resoAp + linkAp + fieldAp;
var captureAp = CAPTURE_PORTAL + 8 * DEPLOY_RESONATOR + COMPLETION_BONUS;
var totalAp = destroyAp + captureAp;
return {
totalAp: totalAp,
destroyAp: destroyAp,
captureAp: captureAp,
resoCount: resoCount,
linkCount: linkCount,
fieldCount: fieldCount
}
}
window.plugin.apList.getEffectiveLevel = function(portal) {
var effectiveEnergy = 0;
var effectiveLevel = 0;
var resosStats = plugin.apList.getResonatorsStats(portal);
// Calculate effective energy
var effectOfShields = plugin.apList.getShieldsEffect(portal);
// If avgResoDistance is 0, 8 resonators in the same place and can be treated as 1 resonator.
// So the minimum effect of resonator distance is 1/8
var effectOfResoDistance = (1 + (resosStats.avgResoDistance / HACK_RANGE) * 7 ) / 8;
effectiveEnergy = resosStats.currentEnergy * effectOfShields * effectOfResoDistance;
// Calculate effective level
for(var i = MAX_PORTAL_LEVEL; i >= 0; i--) {
var baseLevel = i;
var baseLevelEnergy = RESO_NRG[baseLevel] * 8;
if(effectiveEnergy >= baseLevelEnergy) {
var energyToNextLevel = baseLevel === MAX_PORTAL_LEVEL
? baseLevelEnergy - RESO_NRG[MAX_PORTAL_LEVEL - 1] * 8 // Extrapolate
: RESO_NRG[baseLevel + 1] * 8 - baseLevelEnergy; // Interpolate
var additionalLevel = (effectiveEnergy - baseLevelEnergy) / energyToNextLevel;
effectiveLevel = baseLevel + additionalLevel;
break;
}
}
// Account for damage do to player by portal
var portalLevel = parseInt(getPortalLevel(portal));
if(effectiveLevel < portalLevel) {
var energyPect = resosStats.currentEnergy / resosStats.totalEnergy;
effectiveLevel = effectiveLevel * (1-energyPect) + portalLevel * energyPect;
}
return {
effectiveLevel: Math.round(effectiveLevel * 10) / 10,
effectiveEnergy: parseInt(effectiveEnergy),
effectOfShields: Math.round(effectOfShields * 100) / 100,
effectOfResoDistance: Math.round(effectOfResoDistance * 100) / 100,
originLevel: portalLevel
};
}
window.plugin.apList.getResonatorsStats = function(portal) {
var totalEnergy = 0;
var currentEnergy = 0;
var avgResoDistance = 0;
$.each(portal.resonatorArray.resonators, function(ind, reso) {
if (!reso)
return true;
totalEnergy += RESO_NRG[reso.level];
currentEnergy += reso.energyTotal;
avgResoDistance += (reso.distanceToPortal / 8);
});
return {
totalEnergy: totalEnergy,
currentEnergy: currentEnergy,
avgResoDistance: avgResoDistance};
}
window.plugin.apList.getShieldsEffect = function(portal) {
// shield effect: each shield's mitigation value is assumed to be the percentage of the damage it will absorb
// the rest of the damage gets through to the next shield, and so on.
// so, to calculate the total protection, we multiply the fractions of damage allowed through each shield
// to get a final figure of how much damage gets through
// e.g.
// one shield: mitigation 10 - lets 90% of the damage through
// two shields: mitigation 20 and 30 - first one lets 80% through, second 70% of the remaining
// so final amount let through = 0.8 * 0.7 = 0.56 = 56% damage let through
// four shields: mitigation 30 - 70% through each = 0.7 * 0.7 * 0.7 * 0.7 = 0.24 = 24% damage gets through all four
var shieldsEffect = 1;
$.each(portal.portalV2.linkedModArray, function(ind, mod) {
if(!mod)
return true;
if(!mod.stats.MITIGATION)
return true;
shieldsEffect *= (1 - parseInt(mod.stats.MITIGATION)/100.0);
});
return shieldsEffect;
}
// For using in .sort(func) of sortedPortals
// Use options in plugin.apList.sortOptions. Each type of sortBy has
// array of options. Option consist of an ordering and a property chain.
//
// Sorting done by loop through the options, get the property by
// property chain of each option, compare the property of two object
// with the ordering of option and return the result when the first
// difference is found.
window.plugin.apList.comparePortal = function(a,b) {
var result = 0;
var options = plugin.apList.sortOptions[plugin.apList.sortBy];
$.each(options, function(indO, option) {
var aProperty = a;
var bProperty = b;
// Walking down the chain
$.each(option.chain, function(indPN, propertyName) {
aProperty = aProperty[propertyName];
bProperty = bProperty[propertyName];
});
// compare next property if equal
if(aProperty === bProperty) return true;
result = (aProperty > bProperty ? 1 : -1) * option.order;
return false;
});
return result;
}
// FEATURE TOGGLES AND INTERACTION HANDLER ///////////////////////////////////////
window.plugin.apList.enableCache = function() {
plugin.apList.useCachedPortals = true;
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
window.plugin.apList.disableCache = function() {
plugin.apList.useCachedPortals = false;
plugin.apList.cachedPortals = {};
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
window.plugin.apList.selectPortal = function(guid) {
// Add error catching to avoid following link of portal if error
// occurred in renderPortalDetails or hooked plugin
try {
renderPortalDetails(guid);
} catch(e) {
console.error(e.message);
console.log(e.stack);
console.log('Skipping error in renderPortalDetails or hooked plugin')
}
plugin.apList.setPortalLocationIndicator(guid);
}
window.plugin.apList.setPortalLocationIndicator = function(guid) {
var portal = window.portals[guid];
if(!portal) return;
var startRadius = screen.availWidth / 2;
var portalRadius = portal.options.radius;
var latlng = portal.getLatLng();
var property = {
radius: startRadius,
fill: false,
color: COLOR_SELECTED_PORTAL,
weight: 2,
opacity: 1,
portalRadius: portalRadius,
clickable: false };
if(plugin.apList.portalLocationIndicator)
map.removeLayer(plugin.apList.portalLocationIndicator);
if(plugin.apList.animTimeout)
clearTimeout(plugin.apList.animTimeout);
plugin.apList.portalLocationIndicator = L.circleMarker(latlng, property).addTo(map);
plugin.apList.animTimeout = setTimeout(plugin.apList.animPortalLocationIndicator,100);
}
window.plugin.apList.animPortalLocationIndicator = function() {
var radius = plugin.apList.portalLocationIndicator.options.radius;
var portalRadius = plugin.apList.portalLocationIndicator.options.portalRadius
if(radius > portalRadius) {
var step = radius / 3;
if(radius < 80) step = step / 3;
var newRadius = plugin.apList.portalLocationIndicator.options.radius -= step;
plugin.apList.portalLocationIndicator.setRadius(newRadius);
if(plugin.apList.animTimeout)
clearTimeout(plugin.apList.animTimeout);
plugin.apList.animTimeout = setTimeout(plugin.apList.animPortalLocationIndicator,100);
} else {
map.removeLayer(plugin.apList.portalLocationIndicator);
}
}
window.plugin.apList.changePage = function(step, toEnd) {
var side = plugin.apList.displaySide;
var oldPage = plugin.apList.currentPage[side];
if(toEnd) {
if(step < 0) plugin.apList.currentPage[side] = 1;
if(step > 0) plugin.apList.currentPage[side] = plugin.apList.totalPage[side]
} else {
plugin.apList.currentPage[side] += step;
if(plugin.apList.currentPage[side] < 1)
plugin.apList.currentPage[side] = 1;
if(plugin.apList.currentPage[side] > plugin.apList.totalPage[side])
plugin.apList.currentPage[side] = plugin.apList.totalPage[side];
}
if(plugin.apList.currentPage[side] !== oldPage)
plugin.apList.updatePortalTable(side);
}
window.plugin.apList.changeSorting = function(sortBy) {
var oldSortBy = plugin.apList.sortBy;
plugin.apList.sortBy = sortBy;
if(plugin.apList.sortBy !== oldSortBy) {
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
}
window.plugin.apList.clearDestroyPortals = function() {
plugin.apList.destroyPortalsGuid = new Array();
plugin.apList.updateSortedPortals();
plugin.apList.updatePortalTable(plugin.apList.displaySide);
}
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);
}
// Change display table to friendly portals
window.plugin.apList.displayFriendly = function() {
plugin.apList.changeDisplaySide(plugin.apList.SIDE_FRIENDLY);
}
// Change display table to enemy portals
window.plugin.apList.displayEnemy = function() {
plugin.apList.changeDisplaySide(plugin.apList.SIDE_ENEMY);
}
window.plugin.apList.changeDisplaySide = function(side) {
var isChange = (plugin.apList.displaySide !== side);
var scrollTo = 0;
if(isChange) {
plugin.apList.displaySide = side;
plugin.apList.updatePortalTable(side);
plugin.apList.toggleSideLabel(side);
scrollTo = $("#ap-list").position().top + $("#ap-list").outerHeight()
- $("#sidebar").height() + $("#sidebar").scrollTop();
}
$('#sidebar').scrollTop(scrollTo);
}
window.plugin.apList.toggleSideLabel = function(side) {
$.each(plugin.apList.sides, function(ind,key) {
var labelClass = plugin.apList.sideLabelClass[key];
var opacity = (key === side) ? 1.0 : 0.5;
$(labelClass).css("opacity", opacity);
});
}
window.plugin.apList.hideReloadLabel = function() {
$('#ap-list-reload').hide();
}
window.plugin.apList.showReloadLabel = function() {
$('#ap-list-reload').show();
}
// SETUP /////////////////////////////////////////////////////////////////////////
window.plugin.apList.setupVar = function() {
plugin.apList.sides[plugin.apList.SIDE_FRIENDLY] = plugin.apList.SIDE_FRIENDLY;
plugin.apList.sides[plugin.apList.SIDE_ENEMY] = plugin.apList.SIDE_ENEMY;
plugin.apList.playerApGainFunc[plugin.apList.SIDE_FRIENDLY]
= plugin.apList.getDeployOrUpgradeApGain;
plugin.apList.playerApGainFunc[plugin.apList.SIDE_ENEMY]
= plugin.apList.getAttackApGain;
plugin.apList.sideLabelClass[plugin.apList.SIDE_FRIENDLY]
= "#ap-list-frd";
plugin.apList.sideLabelClass[plugin.apList.SIDE_ENEMY]
= "#ap-list-eny";
plugin.apList.sortedPortals[plugin.apList.SIDE_FRIENDLY] = new Array();
plugin.apList.sortedPortals[plugin.apList.SIDE_ENEMY] = new Array();
}
window.plugin.apList.setupSorting = function() {
var optionELAsc = {
order: plugin.apList.SORT_ASC,
chain: ['effectiveLevel','effectiveLevel']};
var optionAPDesc = {
order: plugin.apList.SORT_DESC,
chain: ['playerApGain','totalAp']};
var optionGuidDesc = {
order: plugin.apList.SORT_DESC,
chain: ['guid']};
// order by EL -> AP -> guid
plugin.apList.sortOptions[plugin.apList.SORT_BY_EL] = [optionELAsc, optionAPDesc, optionGuidDesc];
// order by AP -> EL -> guid
plugin.apList.sortOptions[plugin.apList.SORT_BY_AP] = [optionAPDesc, optionELAsc, optionGuidDesc];
}
// Setup table columns for header builder and row builder
window.plugin.apList.setupTableColumns = function() {
var enemyColumns = new Array();
var friendlyColumns = new Array();
// AP and Eff. LV columns are same in enemy and friendly table
var apColumn = {
header: 'AP',
headerOnClick: 'plugin.apList.changeSorting(plugin.apList.SORT_BY_AP);',
headerTooltip: 'Click to sort by AP',
cssClass: 'ap-list-td-ap',
contentFunction: plugin.apList.getPortalApText
};
var effectiveLevelColumn = {
header: 'EL',
headerOnClick: 'plugin.apList.changeSorting(plugin.apList.SORT_BY_EL);',
headerTooltip: 'Effective Level\nClick to sort by EL',
cssClass: 'ap-list-td-eff-lv',
contentFunction: plugin.apList.getPortalEffectiveLvText
};
// Columns: Checkbox | Portal | AP | Eff. LV
enemyColumns.push({
headerFunction: plugin.apList.getHeaderCheckbox,
headerTooltip: 'Unselect all',
cssClass: 'ap-list-td-checkbox',
contentFunction: plugin.apList.getPortalDestroyCheckbox
});
enemyColumns.push({
header: 'Portal',
cssClass: 'ap-list-td-link ap-list-td-link-eny',
contentFunction: plugin.apList.getPortalLink
});
enemyColumns.push(apColumn);
enemyColumns.push(effectiveLevelColumn);
// Columns: Portal | AP | Eff. LV
friendlyColumns.push({
header: 'Portal',
cssClass: 'ap-list-td-link ap-list-td-link-frd',
contentFunction: plugin.apList.getPortalLink
});
friendlyColumns.push(apColumn);
friendlyColumns.push(effectiveLevelColumn);
plugin.apList.tableColumns[plugin.apList.SIDE_ENEMY] = enemyColumns;
plugin.apList.tableColumns[plugin.apList.SIDE_FRIENDLY] = friendlyColumns;
}
window.plugin.apList.setupCSS = function() {
$("<style>")
.prop("type", "text/css")
.html("@@INCLUDESTRING:plugins/ap-list.css@@")
.appendTo("head");
}
window.plugin.apList.setupList = function() {
var content = '<div id="ap-list">'
+ '<span id="ap-list-side-labels">'
+ '<span id="ap-list-eny">'
+ '<a href="#" onclick="window.plugin.apList.displayEnemy();return false;">Enemy</a>'
+ '</span>'
+ '<span id="ap-list-frd">'
+ '<a href="#" onclick="window.plugin.apList.displayFriendly();return false;">Friendly</a>'
+ '</span>'
+ '</span>'
+ '<span id="ap-list-reload">'
+ '<a href="#" title="Clear list and reload" onclick="window.plugin.apList.disableCache();'
+ 'plugin.apList.hideReloadLabel();return false;">↻ R</a>'
+ '</span>'
+ '<div id="ap-list-table"></div>'
+ '<span id="ap-list-misc-info" title="Stats">...</span>'
+ '<span id="ap-list-pagination"></span>'
+ '</div>';
$('#sidebar').append(content);
$('#ap-list-reload').hide();
}
window.plugin.apList.setupPagination = function() {
var content = '<div class="ap-list-center-div">'
+ '<div id="ap-list-first-p" class="ap-list-page-control" onclick="plugin.apList.changePage(-1, true);">'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-half"/>'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-half"/>'
+ '</div>'
+ '<div id="ap-list-next-p" class="ap-list-page-control" onclick="plugin.apList.changePage(-1);">'
+ '<div class="ap-list-triangle ap-list-triangle-left ap-list-triangle-left-full"/>'
+ '</div>'
+ '<div id="ap-list-current-p" class="ap-list-page-text">1</div>'
+ '<div id="ap-list-page-slash" class="ap-list-page-text">/</div>'
+ '<div id="ap-list-total-p" class="ap-list-page-text">1</div>'
+ '<div id="ap-list-prev-p" class="ap-list-page-control" onclick="plugin.apList.changePage(1);">'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-full"/>'
+ '</div>'
+ '<div id="ap-list-last-p" class="ap-list-page-control" onclick="plugin.apList.changePage(1, true);">'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-half"/>'
+ '<div class="ap-list-triangle ap-list-triangle-right ap-list-triangle-right-half"/>'
+ '</div>'
+ '<div class="spacer" style="clear: both;"></div>'// fix collapsion of parent caused by inner div's float:left
+ '</div>';
$('#ap-list-pagination').html(content);
}
window.plugin.apList.setupMapEvent = function() {
map.on('zoomstart', function() {
plugin.apList.setupMapEvent.zoomLevelBefore = map.getZoom();
// Stop changing cacheBounds if cache enabled
if(!plugin.apList.useCachedPortals)
plugin.apList.cacheBounds = map.getBounds();
});
map.on('zoomend', function() {
// if zooming in and cache not yet enable, enable it
if(!plugin.apList.useCachedPortals
&& map.getZoom() > plugin.apList.setupMapEvent.zoomLevelBefore) {
plugin.apList.enableCache();
plugin.apList.showReloadLabel();
}
});
map.on('moveend zoomend', function() {
// disable cache after out of cache bounds
if(plugin.apList.useCachedPortals) {
var currentBounds = map.getBounds();
if(!plugin.apList.cacheBounds.contains(currentBounds)) {
plugin.apList.disableCache();
plugin.apList.hideReloadLabel();
}
}
});
}
var setup = function() {
window.plugin.apList.setupVar();
window.plugin.apList.setupSorting();
window.plugin.apList.setupTableColumns();
window.plugin.apList.setupCSS();
window.plugin.apList.setupList();
window.plugin.apList.setupPagination();
window.plugin.apList.setupMapEvent();
window.addHook('mapDataRefreshEnd', window.plugin.apList.handleUpdate);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,141 @@
// ==UserScript==
// @id iitc-plugin-compute-ap-stats@Hollow011
// @name IITC plugin: Compute AP statistics
// @category Info
// @version 0.3.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Displays the per-team AP gains available in the current view.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.compAPStats = function() {};
window.plugin.compAPStats.setupCallback = function() {
// add a new div to the bottom of the sidebar and style it
$('#sidebar').append('<div id="available_ap_display"></div>');
$('#available_ap_display').css({'color':'#ffce00', 'font-size':'90%', 'padding':'4px 2px'});
// do an initial calc for sidebar sizing purposes
window.plugin.compAPStats.onPositionMove();
// make the value update when the map data updates
window.addHook('mapDataRefreshEnd', window.plugin.compAPStats.onPositionMove);
}
window.plugin.compAPStats.onPositionMove = function() {
var result = window.plugin.compAPStats.compAPStats();
$('#available_ap_display').html('Available AP in this area:<table>'
+ '<tr><td>Enlightened:</td><td style="text-align:right">' + digits(result[1]) + '</td></tr>'
+ '<tr><td>Resistance:</td><td style="text-align:right">' + digits(result[0]) + '</td></tr>'
+ '</table>');
}
window.plugin.compAPStats.missingResonatorAP = function(portal) {
var resAP = 0;
var missing_resonators = 0;
$.each(portal.resonatorArray.resonators, function(ind, reso) {
if(reso === null) {
missing_resonators++;
}
});
if(missing_resonators > 0) {
resAP = window.DEPLOY_RESONATOR * missing_resonators;
resAP += window.COMPLETION_BONUS;
}
return(resAP);
};
window.plugin.compAPStats.compAPStats = function() {
var totalAP_RES = 0;
var totalAP_ENL = 0;
var allResEdges = [];
var allResFields = [];
var allEnlEdges = [];
var allEnlFields = [];
var displayBounds = map.getBounds();
// Grab every portal in the viewable area and compute individual AP stats
$.each(window.portals, function(ind, portal) {
var d = portal.options.details;
// eliminate offscreen portals (selected, and in padding)
if(!displayBounds.contains(portal.getLatLng())) return true;
var portalStats = getAttackApGain(d);
var portalSum = portalStats.resoAp + portalStats.captureAp;
if (getTeam(d) === TEAM_ENL) {
totalAP_RES += portalSum;
$.each(d.portalV2.linkedEdges||[], function(ind, edge) {
if(!edge) return true;
allEnlEdges.push(edge.edgeGuid);
});
$.each(d.portalV2.linkedFields||[], function(ind, field) {
if(!field) return true;
allEnlFields.push(field);
});
totalAP_ENL += window.plugin.compAPStats.missingResonatorAP(d);
}
else if (getTeam(d) === TEAM_RES) {
totalAP_ENL += portalSum;
$.each(d.portalV2.linkedEdges||[], function(ind, edge) {
if(!edge) return true;
allResEdges.push(edge.edgeGuid);
});
$.each(d.portalV2.linkedFields||[], function(ind, field) {
if(!field) return true;
allResFields.push(field);
});
totalAP_RES += window.plugin.compAPStats.missingResonatorAP(d);
} else {
// it's a neutral portal, potential for both teams. by definition no fields or edges
totalAP_ENL += portalSum;
totalAP_RES += portalSum;
}
});
// Compute team field AP
allResFields = uniqueArray(allResFields);
totalAP_ENL += (allResFields.length * DESTROY_FIELD);
allEnlFields = uniqueArray(allEnlFields);
totalAP_RES += (allEnlFields.length * DESTROY_FIELD);
// Compute team Link AP
allResEdges = uniqueArray(allResEdges);
totalAP_ENL += (allResEdges.length * DESTROY_LINK);
allEnlEdges = uniqueArray(allEnlEdges);
totalAP_RES += (allEnlEdges.length * DESTROY_LINK);
return [totalAP_RES, totalAP_ENL];
}
var setup = function() {
window.plugin.compAPStats.setupCallback();
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,811 @@
// ==UserScript==
// @id iitc-plugin-draw-resonators@xelio
// @name IITC plugin: Draw resonators
// @category Layer
// @version 0.4.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Draw resonators on map. With stylers to highlight resonators with specific criteria.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.drawResonators = function() {};
window.plugin.drawResonators.options;
window.plugin.drawResonators.render;
//////// Render for handling render of resonators ////////
// As long as 'window.Render.prototype.createPortalEntity' delete and recreate portal
// on any change of data, this resonator render should make resonator create and remove
// with portal correctly.
//
// Resonators will create when
// 1.Portal added to map
// 2.Zooming in to enable zoom level
//
// Resonators will remove when
// 1.Portal removed from map
// 2.Zooming out beyond enable zoom level
window.plugin.drawResonators.Render = function(options) {
this.enableZoomLevel = options['enableZoomLevel'];
this.useStyler = '';
this.stylers = {};
this.resonators = {};
this.resonatorLayerGroup = new L.LayerGroup();
this.addStyler(new window.plugin.drawResonators.Styler());
this.beforeZoomLevel = map.getZoom();
this.portalAdded = this.portalAdded.bind(this);
this.createResonatorEntities = this.createResonatorEntities.bind(this);
this.deleteResonatorEntities = this.deleteResonatorEntities.bind(this);
this.handleResonatorEntitiesBeforeZoom = this.handleResonatorEntitiesBeforeZoom.bind(this);
this.handleResonatorEntitiesAfterZoom = this.handleResonatorEntitiesAfterZoom.bind(this);
this.handleEnableZoomLevelChange = this.handleEnableZoomLevelChange.bind(this);
this.portalSelectionChange = this.portalSelectionChange.bind(this);
this.changeStyler = this.changeStyler.bind(this);
this.getStylersList = this.getStylersList.bind(this);
};
window.plugin.drawResonators.Render.prototype.registerHook = function() {
window.addHook('portalAdded', this.portalAdded);
window.addHook('portalSelected', this.portalSelectionChange);
window.map.on('zoomstart', this.handleResonatorEntitiesBeforeZoom);
window.map.on('zoomend', this.handleResonatorEntitiesAfterZoom);
}
window.plugin.drawResonators.Render.prototype.portalAdded = function(data) {
var marker = data.portal;
var render = this;
marker.on('add', function() {
render.createResonatorEntities(this); // the 'this' in here is the portal.
});
marker.on('remove', function() {
render.deleteResonatorEntities(this.options.guid); // the 'this' in here is the portal.
});
}
window.plugin.drawResonators.Render.prototype.createResonatorEntities = function(portal) {
// No need to check for existing resonators, as old resonators should be removed with the portal marker.
if(!this.isResonatorsShow()) return;
var portalDetails = portal.options.details;
var resonatorsWithConnector = new L.LayerGroup()
var portalLatLng = [portalDetails.locationE6.latE6/1E6, portalDetails.locationE6.lngE6/1E6];
var portalSelected = selectedPortal === portal.options.guid;
for(var i in portalDetails.resonatorArray.resonators) {
resoData = portalDetails.resonatorArray.resonators[i];
if(resoData === null) continue;
var resoLatLng = this.getResonatorLatLng(resoData.distanceToPortal, resoData.slot, portalLatLng);
var resoMarker = this.createResoMarker(resoData, resoLatLng, portalSelected);
var connMarker = this.createConnMarker(resoData, resoLatLng, portalLatLng, portalSelected);
resonatorsWithConnector.addLayer(resoMarker);
resonatorsWithConnector.addLayer(connMarker);
}
resonatorsWithConnector.options = {
details: portalDetails.resonatorArray.resonators,
guid: portal.options.guid
};
this.resonators[portal.options.guid] = resonatorsWithConnector;
this.resonatorLayerGroup.addLayer(resonatorsWithConnector);
// bring portal in front of resonator connector
portal.bringToFront();
}
window.plugin.drawResonators.Render.prototype.createResoMarker = function(resoData, resoLatLng, portalSelected) {
var resoProperty = this.getStyler().getResonatorStyle(resoData, portalSelected);
resoProperty.type = 'resonator';
resoProperty.details = resoData;
var reso = L.circleMarker(resoLatLng, resoProperty);
return reso;
}
window.plugin.drawResonators.Render.prototype.createConnMarker = function(resoData, resoLatLng, portalLatLng, portalSelected) {
var connProperty = this.getStyler().getConnectorStyle(resoData, portalSelected);
connProperty.type = 'connector';
connProperty.details = resoData;
var conn = L.polyline([portalLatLng, resoLatLng], connProperty);
return conn;
}
window.plugin.drawResonators.Render.prototype.getResonatorLatLng = function(dist, slot, portalLatLng) {
// offset in meters
var dn = dist*SLOT_TO_LAT[slot];
var de = dist*SLOT_TO_LNG[slot];
// Coordinate offset in radians
var dLat = dn/EARTH_RADIUS;
var dLon = de/(EARTH_RADIUS*Math.cos(Math.PI/180*portalLatLng[0]));
// OffsetPosition, decimal degrees
var lat0 = portalLatLng[0] + dLat * 180/Math.PI;
var lon0 = portalLatLng[1] + dLon * 180/Math.PI;
return [lat0, lon0];
}
window.plugin.drawResonators.Render.prototype.deleteResonatorEntities = function(portalGuid) {
if (!(portalGuid in this.resonators)) return;
var r = this.resonators[portalGuid];
this.resonatorLayerGroup.removeLayer(r);
delete this.resonators[portalGuid];
}
// Save zoom level before zoom, use to determine redraw of resonator
window.plugin.drawResonators.Render.prototype.handleResonatorEntitiesBeforeZoom = function() {
this.beforeZoomLevel = map.getZoom();
}
window.plugin.drawResonators.Render.prototype.handleResonatorEntitiesAfterZoom = function() {
if(!this.isResonatorsShow()) {
this.clearAllResonators();
return;
}
// Draw all resonators if they were not drawn
if(!this.isResonatorsShowBeforeZoom()) {
this.drawAllResonators();
}
}
window.plugin.drawResonators.Render.prototype.handleEnableZoomLevelChange = function(zoomLevel) {
this.enableZoomLevel = zoomLevel;
if(!this.isResonatorsShow()) {
this.clearAllResonators();
return;
}
// Draw all resonators if they were not drawn
if(!Object.keys(this.resonators).length > 0) {
this.drawAllResonators();
}
}
window.plugin.drawResonators.Render.prototype.clearAllResonators = function() {
this.resonatorLayerGroup.clearLayers();
this.resonators = {};
}
window.plugin.drawResonators.Render.prototype.drawAllResonators = function() {
var render = this;
// loop through level of portals, only draw if the portal is shown on map
for (var guid in window.portals) {
var portal = window.portals[guid];
// FIXME: need to find a proper way to check if a portal is added to the map without depending on leaflet internals
// (and without depending on portalsLayers either - that's IITC internal)
if (portal._map) {
render.createResonatorEntities(portal);
}
}
}
window.plugin.drawResonators.Render.prototype.portalSelectionChange = function(data) {
this.toggleSelectedStyle(data.selectedPortalGuid);
this.toggleSelectedStyle(data.unselectedPortalGuid);
}
window.plugin.drawResonators.Render.prototype.toggleSelectedStyle = function(portalGuid) {
if (!(portalGuid in this.resonators)) return;
var render = this;
var portalSelected = selectedPortal === portalGuid;
var r = this.resonators[portalGuid];
r.eachLayer(function(entity) {
var style;
if(entity.options.type === 'resonator') {
style = render.getStyler().getResonatorStyle(entity.options.details, portalSelected);
} else {
style = render.getStyler().getConnectorStyle(entity.options.details, portalSelected);
}
entity.setStyle(style);
});
}
window.plugin.drawResonators.Render.prototype.addStyler = function(styler) {
this.stylers[styler.name] = styler;
}
window.plugin.drawResonators.Render.prototype.getStylersList = function() {
return Object.keys(this.stylers);
}
window.plugin.drawResonators.Render.prototype.getStyler = function() {
var stylerName = this.useStyler in this.stylers ? this.useStyler : 'Default';
return this.stylers[stylerName];
}
// Change if styler need change, and redraw all resonators using new styler
window.plugin.drawResonators.Render.prototype.changeStyler = function(name) {
if (name === this.useStyler) return;
for(stylerName in this.stylers) {
if(stylerName === name) {
if(this.stylers[this.useStyler]) this.stylers[this.useStyler].onDisableFunc();
this.useStyler = stylerName;
this.stylers[this.useStyler].onEnableFunc();
this.clearAllResonators();
this.drawAllResonators();
return;
}
}
}
window.plugin.drawResonators.Render.prototype.refreshStyler = function() {
this.clearAllResonators();
this.drawAllResonators();
}
window.plugin.drawResonators.Render.prototype.isResonatorsShow = function() {
return map.getZoom() >= this.enableZoomLevel;
}
window.plugin.drawResonators.Render.prototype.isResonatorsShowBeforeZoom = function() {
return this.beforeZoomLevel >= this.enableZoomLevel;
}
//////// Styler for getting resonator and connector style ////////
window.plugin.drawResonators.Styler = function(options) {
options = options || {};
this.name = options['name'] || 'Default';
this.otherOptions = options['otherOptions'];
this.getResonatorStyle = options['resonatorStyleFunc'] || this.defaultResonatorStyle;
this.getConnectorStyle = options['connectorStyleFunc'] || this.defaultConnectorStyle;
this.onEnableFunc = options['onEnableFunc'] || function() {};
this.onDisableFunc = options['onDisableFunc'] || function() {};
}
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_SELECTED = {
color: '#fff',
weight: 1.1,
radius: 4,
opacity: 1,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_NON_SELECTED = {
color: '#aaa',
weight: 1,
radius: 3,
opacity: 1,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_LINE_SELECTED = {
opacity: 0.7,
weight: 3,
color: '#FFA000',
dashArray: '0,10' + (new Array(25).join(',8,4')),
fill: false,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_LINE_NON_SELECTED = {
opacity: 0.25,
weight: 2,
color: '#FFA000',
dashArray: '0,10' + (new Array(25).join(',8,4')),
fill: false,
clickable: false};
window.plugin.drawResonators.Styler.prototype.defaultResonatorStyle = function(resoDetail, selected) {
var resoSharedStyle = selected
? this.DEFAULT_OPTIONS_RESONATOR_SELECTED
: this.DEFAULT_OPTIONS_RESONATOR_NON_SELECTED;
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level],
}, resoSharedStyle);
return resoStyle;
}
window.plugin.drawResonators.Styler.prototype.defaultConnectorStyle = function(resoDetail, selected) {
var connStyle = selected
? this.DEFAULT_OPTIONS_RESONATOR_LINE_SELECTED
: this.DEFAULT_OPTIONS_RESONATOR_LINE_NON_SELECTED;
return connStyle;
}
//////// Options for storing and loading options ////////
window.plugin.drawResonators.Options = function() {
this._options = {};
this._callbacks = {};
}
window.plugin.drawResonators.Options.prototype.addCallback = function(name, callback) {
if (!this._callbacks[name]) {
this._callbacks[name] = [];
}
this._callbacks[name].push(callback);
}
window.plugin.drawResonators.Options.prototype.newOption = function(name, defaultValue) {
this._options[name] = this.loadLocal(this.getStorageKey(name), defaultValue)
}
window.plugin.drawResonators.Options.prototype.getOption = function(name) {
return this._options[name];
}
window.plugin.drawResonators.Options.prototype.removeOption = function(name) {
delete this._options[name];
delete this._callbacks[name];
}
window.plugin.drawResonators.Options.prototype.changeOption = function(name, value) {
if(!(name in this._options)) return false;
if(value === this._options[name]) return false;
this._options[name] = value;
this.storeLocal(this.getStorageKey(name), this._options[name]);
if (this._callbacks[name] !== null) {
for(var i in this._callbacks[name]) {
this._callbacks[name][i](value);
}
}
}
window.plugin.drawResonators.Options.prototype.getStorageKey = function(name) {
return 'plugin-drawResonators-option-' + name;
}
window.plugin.drawResonators.Options.prototype.loadLocal = function(key, defaultValue) {
var objectJSON = localStorage[key];
if(objectJSON) {
return JSON.parse(objectJSON);
} else {
return defaultValue;
}
}
window.plugin.drawResonators.Options.prototype.storeLocal = function(key, value) {
if(typeof(value) !== 'undefined' && value !== null) {
localStorage[key] = JSON.stringify(value);
} else {
localStorage.removeItem(key);
}
}
//////// Dialog
window.plugin.drawResonators.Dialog = function() {
this._dialogEntries = {};
}
window.plugin.drawResonators.Dialog.prototype.addLink = function() {
$('#toolbox').append('<a id="draw-reso-show-dialog" onclick="window.plugin.drawResonators.dialog.show();">Resonators</a> ');
}
window.plugin.drawResonators.Dialog.prototype.addEntry = function(name, dialogEntry) {
this._dialogEntries[name] = dialogEntry;
this.change();
}
window.plugin.drawResonators.Dialog.prototype.removeEntry = function(name) {
delete this._dialogEntries[name];
this.change();
}
window.plugin.drawResonators.Dialog.prototype.show = function() {
window.dialog({html: this.getDialogHTML(), title: 'Resonators', modal: true, id: 'draw-reso-setting'});
// Attach entries event
for(var name in this._dialogEntries) {
var events = this._dialogEntries[name].getOnEvents();
for(var i in events) {
var event = events[i];
$('#draw-reso-dialog').on(event.event, '#' + event.id, event.callback);
}
}
}
window.plugin.drawResonators.Dialog.prototype.change = function() {
if($('#draw-reso-dialog').length > 0) this.show();
}
window.plugin.drawResonators.Dialog.prototype.getDialogHTML = function() {
var html = '<div id="draw-reso-dialog">'
for(var name in this._dialogEntries) {
html += '<div>'
+ this._dialogEntries[name].getHTML()
+ '</div>';
}
html += '</div>';
return html;
}
//////// ListDialogEntry
window.plugin.drawResonators.ListDialogEntry = function(options) {
this._name = options['name'];
this._label = options['label'];
this._valueFunc = options['valueFunc'];
this._valuesList = options['valuesList'];
this._valuesListFunc = options['valuesListFunc'];
this._onChangeCallback = options['onChangeCallback'];
}
window.plugin.drawResonators.ListDialogEntry.prototype.getHTML = function() {
var curValue = this._valueFunc();
var valuesList = this._valuesList ? this._valuesList : this._valuesListFunc();
var html = '<label for="' + this.getSelectId() + '">'
+ this._label + ': '
+ '</label>'
+ '<select id="' + this.getSelectId() + '">';
var noLabel = valuesList instanceof Array;
for(var label in valuesList) {
var selected = valuesList[label] === curValue;
html += '<option value="' + valuesList[label] + '" '
+ (selected ? 'selected="selected"' : '')
+'>'
+ (noLabel ? valuesList[label] : label)
+ '</option>';
}
html += '</select>';
return html;
}
window.plugin.drawResonators.ListDialogEntry.prototype.getOnEvents = function() {
return [{'event': 'change',
'id': this.getSelectId(),
'callback': this._onChangeCallback
}];
}
window.plugin.drawResonators.ListDialogEntry.prototype.getSelectId = function() {
return 'draw-reso-option-' + this._name;
}
//////// TextboxDialogEntry
window.plugin.drawResonators.TextboxDialogEntry = function(options) {
this._name = options['name'];
this._label = options['label'];
this._valueFunc = options['valueFunc'];
this._onChangeCallback = options['onChangeCallback'];
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getHTML = function() {
var curValue = this._valueFunc();
var html = '<label for="' + this.getInputId() + '">'
+ this._label + ': '
+ '</label>'
+ '<input type="text" size="20" id="' + this.getInputId() + '" '
+ 'value="' + curValue + '" />';
return html;
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getOnEvents = function() {
return [{'event': 'change',
'id': this.getInputId(),
'callback': this._onChangeCallback
}];
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getInputId = function() {
return 'draw-reso-option-' + this._name;
}
window.plugin.drawResonators.setupStyler = function() {
var thisPlugin = window.plugin.drawResonators;
var highlightedReso = {color: '#fff', weight: 2, radius: 4, opacity: 1, clickable: false};
var normalReso = {color: '#aaa', weight: 1, radius: 3, opacity: 1, clickable: false};
var selectedReso = {color: '#eee', weight: 1.1, radius: 4, opacity: 1, clickable: false};
var highlightedConn = {opacity: 0.7, weight: 3, color: '#FFA000', dashArray: '0,10,999', color: '#FFA000', fill: false, clickable: false};
var normalConn = {opacity: 0.25, weight: 2, color: '#FFA000', dashArray: '0,10' + (new Array(25).join(',8,4')), fill: false, clickable: false};
var selectedConn = {opacity: 0.7, weight: 3, color: '#FFA000', dashArray: '0,10' + (new Array(25).join(',8,4')), fill: false, clickable: false};
// Styler for highlighting resonators deployed by me
var myReso = {
name: 'Highlight my resonators',
otherOptions: {
'highlightedReso' : highlightedReso,
'normalReso' : normalReso,
'selectedReso' : selectedReso,
'highlightedConn' : highlightedConn,
'normalConn' : normalConn,
'selectedConn' : selectedConn
},
resonatorStyleFunc: function(resoDetail, selected) {
var mine = resoDetail.ownerGuid === PLAYER.guid;
var resoSharedStyle = mine
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (mine ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var mine = resoDetail.ownerGuid === PLAYER.guid;
var connStyle = mine
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(myReso));
// Styler for highlighting L8 resonators
var l8Reso = {
name: 'Highlight L8 resonators',
otherOptions: {
'highlightedReso' : highlightedReso,
'normalReso' : normalReso,
'selectedReso' : selectedReso,
'highlightedConn' : highlightedConn,
'normalConn' : normalConn,
'selectedConn' : selectedConn
},
resonatorStyleFunc: function(resoDetail, selected) {
var l8 = resoDetail.level === 8;
var resoSharedStyle = l8
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (l8 ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var l8 = resoDetail.level === 8;
var connStyle = l8
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(l8Reso));
// Styler for highlighting resonators with less than X% energy
var lessThanXPctReso = {
name: 'Highlight < X% resonators',
otherOptions: {
'highlightedReso': highlightedReso,
'normalReso': normalReso,
'selectedReso': selectedReso,
'highlightedConn': highlightedConn,
'normalConn': normalConn,
'selectedConn': selectedConn,
'pct': 15,
'dialogEntry': new thisPlugin.TextboxDialogEntry({
name: 'resoLessThanPct-pct',
label: 'Percentage',
valueFunc: function() {return thisPlugin.options.getOption('styler-resoLessThanPct-pct')},
onChangeCallback: function(event) {thisPlugin.options.changeOption('styler-resoLessThanPct-pct', parseInt(event.target.value));}
})
},
resonatorStyleFunc: function(resoDetail, selected) {
var highlight = (resoDetail.energyTotal * 100) < (RESO_NRG[resoDetail.level] * this.otherOptions.pct);
var resoSharedStyle = highlight
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level]
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var highlight = (resoDetail.energyTotal * 100) < (RESO_NRG[resoDetail.level] * this.otherOptions.pct);
var connStyle = highlight
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
},
onEnableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
var thisStyler = this;
// Add option
thisPlugin.options.newOption('styler-resoLessThanPct-pct', 15);
thisPlugin.options.addCallback('styler-resoLessThanPct-pct', function(value) {
thisStyler.otherOptions.pct = value;
thisPlugin.render.refreshStyler();
});
thisStyler.otherOptions.pct = thisPlugin.options.getOption('styler-resoLessThanPct-pct');
// Add dialog entry
thisPlugin.dialog.addEntry('resoLessThanPct-pct', this.otherOptions.dialogEntry);
},
onDisableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
// Remove option
thisPlugin.options.removeOption('styler-resoLessThanPct-pct');
// Remove dialog entry
thisPlugin.dialog.removeEntry('resoLessThanPct-pct');
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(lessThanXPctReso));
// Styler for highlighting resonators deployed by specific player
var resoOfSpecificPlayer = {
name: 'Highlight resonators by player',
otherOptions: {
'highlightedReso': highlightedReso,
'normalReso': normalReso,
'selectedReso': selectedReso,
'highlightedConn': highlightedConn,
'normalConn': normalConn,
'selectedConn': selectedConn,
'player': '',
'playerGuid': '',
'dialogEntry': new thisPlugin.TextboxDialogEntry({
name: 'resoOfSpecificPlayer-player',
label: 'Player name',
valueFunc: function() {return thisPlugin.options.getOption('styler-resoOfSpecificPlayer-player')},
onChangeCallback: function(event) {thisPlugin.options.changeOption('styler-resoOfSpecificPlayer-player', event.target.value);}
})
},
resonatorStyleFunc: function(resoDetail, selected) {
var highlight = resoDetail.ownerGuid === this.otherOptions.playerGuid;
var resoSharedStyle = highlight
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (highlight ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var highlight = resoDetail.ownerGuid === this.otherOptions.playerGuid;
var connStyle = highlight
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
},
onEnableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
var thisStyler = this;
// Add option
thisPlugin.options.newOption('styler-resoOfSpecificPlayer-player', '');
thisPlugin.options.addCallback('styler-resoOfSpecificPlayer-player', function(value) {
thisStyler.otherOptions.player = value;
thisStyler.otherOptions.playerGuid = window.playerNameToGuid(value);
thisPlugin.render.refreshStyler();
});
thisStyler.otherOptions.player = thisPlugin.options.getOption('styler-resoOfSpecificPlayer-player');
thisStyler.otherOptions.playerGuid = window.playerNameToGuid(thisStyler.otherOptions.player);
// Add dialog entry
thisPlugin.dialog.addEntry('resoOfSpecificPlayer-player', this.otherOptions.dialogEntry);
},
onDisableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
// Remove option
thisPlugin.options.removeOption('styler-resoOfSpecificPlayer-player');
// Remove dialog entry
thisPlugin.dialog.removeEntry('resoOfSpecificPlayer-player');
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(resoOfSpecificPlayer));
thisPlugin.render.changeStyler(thisPlugin.options.getOption('useStyler'));
}
window.plugin.drawResonators.setupOptions = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize options
thisPlugin.options = new thisPlugin.Options();
thisPlugin.options.newOption('enableZoomLevel', 17);
thisPlugin.options.newOption('useStyler', 'Default');
}
window.plugin.drawResonators.setupDialog = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize dialog
thisPlugin.dialog = new thisPlugin.Dialog();
var enableZoomLevelDialogEntryOptions = {
name: 'enable-zoom-level',
label: 'Enable zoom level',
valueFunc: function() {return thisPlugin.options.getOption('enableZoomLevel')},
valuesList: {'15':15, '16':16, '17':17, '18':18, '19':19, '20':20, 'None':99},
onChangeCallback: function(event) {thisPlugin.options.changeOption('enableZoomLevel', parseInt(event.target.value));}
};
var enableZoomLevelDialogEntry = new thisPlugin.ListDialogEntry(enableZoomLevelDialogEntryOptions);
thisPlugin.dialog.addEntry('enable-zoom-level', enableZoomLevelDialogEntry);
var stylerDialogEntryOptions = {
name: 'use-styler',
label: 'Styler',
valueFunc: function() {return thisPlugin.options.getOption('useStyler')},
valuesListFunc: thisPlugin.render.getStylersList,
onChangeCallback: function(event) {thisPlugin.options.changeOption('useStyler', event.target.value);}
};
var stylerDialogEntry = new thisPlugin.ListDialogEntry(stylerDialogEntryOptions);
thisPlugin.dialog.addEntry('use-styler', stylerDialogEntry);
thisPlugin.dialog.addLink();
}
var setup = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize options
thisPlugin.setupOptions();
// Initialize render
var renderOptions = {'enableZoomLevel': thisPlugin.options.getOption('enableZoomLevel')};
thisPlugin.render = new thisPlugin.Render(renderOptions);
// callback run at option change
thisPlugin.options.addCallback('enableZoomLevel', thisPlugin.render.handleEnableZoomLevelChange);
thisPlugin.options.addCallback('useStyler', thisPlugin.render.changeStyler);
// Initialize Dialog
thisPlugin.setupDialog();
// Initialize styler
thisPlugin.setupStyler();
thisPlugin.render.registerHook();
window.addLayerGroup('Resonators', thisPlugin.render.resonatorLayerGroup, true);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,173 @@
// ==UserScript==
// @id iitc-plugin-favorite-portals@soulBit
// @name IITC plugin: Favorite Portals
// @category Obsolete
// @version 0.2.0.@@DATETIMEVERSION@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] DEPRECATED. Please use "Bookmarks for maps and portals" instead.
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
window.plugin.favoritePortals = function() {};
window.plugin.favoritePortals.portalList = {};
window.plugin.favoritePortals.LOCAL_STORAGE_KEY = "plugin-favorite-portals";
window.plugin.favoritePortals.hasLocalStorage = ('localStorage' in window && window['localStorage'] !== null);
window.plugin.favoritePortals.onDetailsUpdated = function(data) {
$('.linkdetails').prepend("<div title='Favorite this portal' class='toggle-favorite-portal' onclick='window.plugin.favoritePortals.togglePortal()' />");
if(window.plugin.favoritePortals.portalList[window.selectedPortal]) {
$('.toggle-favorite-portal').addClass( 'portal-on' );
window.plugin.favoritePortals.portalList[window.selectedPortal] = window.portals[window.selectedPortal].options;
window.plugin.favoritePortals.savePortals();
}
}
window.plugin.favoritePortals.display = function() {
var output = '';
if (!window.plugin.favoritePortals.hasLocalStorage) {
output += "Favorite portals cannot save any data, please try another browser that supports 'localStorage'.";
} else {
if ($.isEmptyObject(window.plugin.favoritePortals.portalList)) {
output += "No portals have been marked as favorite, click the blue square in the bottom left corner of the portal details to save one.";
} else {
output += "<div class='header'>Portal list (values not current till portal on screen):</div>";
output += "<div class='portal-list-container'>";
var portals = [], dataChanged = false, portalData;
$.each( window.plugin.favoritePortals.portalList, function(i, portal) {
if(window.portals[i]) {
dataChanged = true;
window.plugin.favoritePortals.portalList[ i ] = window.portals[i].options;
}
portalData = (window.portals[i]) ? window.portals[i].options : portal;
portals.push({'guid': i, 'portalData': portalData});
});
if(dataChanged)
window.plugin.favoritePortals.savePortals();
portals.sort(function(a,b) {
var nameA = a.portalData.details.portalV2.descriptiveText.TITLE.toLowerCase();
var nameB = b.portalData.details.portalV2.descriptiveText.TITLE.toLowerCase();
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0;
});
output += "<ol>";
var teamName, energy;
$.each(portals, function(i, portal) {
portalData = portal.portalData;
output += "<li name='" + portal.guid + "'>";
output += "<a class='delete-favorite-portal' title='Delete favorite?' onclick='window.plugin.favoritePortals.onDelete(" + '"' + portal.guid + '"' + ");return false'>X</a>";
output += "<a onclick='window.plugin.favoritePortals.onPortalClicked(" + ' "' + portal.guid + '", [' + (portalData.details.locationE6.latE6 / 1000000) + "," + (portal.portalData.details.locationE6.lngE6 / 1000000) + "]);return false'>" + portalData.details.portalV2.descriptiveText.TITLE + "</a>";
teamName = portalData.details.controllingTeam.team;
output += " - L" + Math.floor( portalData.level );
energy = Math.floor( window.getCurrentPortalEnergy(portalData.details) / window.getPortalEnergy(portalData.details) * 100 );
if(!isNaN(energy))
output += " @" + energy + "%";
output += ": " + ( (teamName === "ALIENS") ? "Enlightened" : teamName[0] + teamName.slice(1).toLowerCase() );
if(portalData.details.portalV2.linkedEdges.length > 0 || portalData.details.portalV2.linkedFields.length > 0)
output += ", " + portalData.details.portalV2.linkedEdges.length + " links & " + portalData.details.portalV2.linkedFields.length + " fields";
output += "</li>";
});
output += "</ol>"
output += "</div>";
}
}
window.dialog({'html': "<div id='favorite-portal-list'>" + output + "</div>", 'title': 'Favorite portals', 'id': 'favorite-portals'});
}
window.plugin.favoritePortals.onDelete = function(guid) {
delete window.plugin.favoritePortals.portalList[ guid ];
if(window.selectedPortal && window.selectedPortal === guid)
$('.toggle-favorite-portal').removeClass( 'portal-on' ).addClass( 'portal-off' );
$("li[name='" + guid + "']").remove();
window.plugin.favoritePortals.savePortals();
}
window.plugin.favoritePortals.onPortalClicked = function(guid, coords) {
window.zoomToAndShowPortal(guid, coords);
$('#dialog-favorite-portals').dialog('close');
}
window.plugin.favoritePortals.togglePortal = function() {
if(window.plugin.favoritePortals.portalList[window.selectedPortal]) {
$('.toggle-favorite-portal').removeClass('portal-on').addClass('portal-off');
delete window.plugin.favoritePortals.portalList[ window.selectedPortal ];
} else {
$('.toggle-favorite-portal').removeClass('portal-off').addClass('portal-on');
window.plugin.favoritePortals.portalList[window.selectedPortal] = window.portals[window.selectedPortal].options;
}
window.plugin.favoritePortals.savePortals();
}
window.plugin.favoritePortals.savePortals = function() {
var portalsObject = {'portals': window.plugin.favoritePortals.portalList};
var portalListJSON = JSON.stringify(portalsObject);
localStorage[window.plugin.favoritePortals.LOCAL_STORAGE_KEY] = portalListJSON;
}
window.plugin.favoritePortals.loadPortals = function() {
var portalListJSON = localStorage[window.plugin.favoritePortals.LOCAL_STORAGE_KEY];
if(!portalListJSON) return;
var portalsObject = JSON.parse(portalListJSON);
window.plugin.favoritePortals.portalList = portalsObject.portals;
}
window.plugin.favoritePortals.setup = function() {
window.plugin.favoritePortals.loadPortals();
window.addHook('portalDetailsUpdated', window.plugin.favoritePortals.onDetailsUpdated);
$('#toolbox').append("<a onclick='window.plugin.favoritePortals.display()' title='Create a list of favorite portals'>Favorite Portals</a>");
$("<style>").prop("type", "text/css").html(".toggle-favorite-portal {\
width: 13px;\
height: 13px;\
margin-left: 10px;\
vertical-align: middle;\
display: inline-block;\
cursor: pointer;\
border: 1px solid #20A8B1;\
}\
.portal-on {\
background-color: #20A8B1;\
}\
.portal-off {\
}\
.linkdetails {\
margin-bottom: 5px;\
}\
.delete-favorite-portal {\
width: 10px;\
height: 10px;\
color: #FFCC00;\
border: 2px solid #20A8B1;\
margin-right: 10px;\
padding-left: 3px;\
padding-right: 3px;\
font-weight: bolder;\
}\
#favorite-portal-list {\
padding: 5px;\
}\
#favorite-portal-list li {\
line-height: 1.8;\
}").appendTo("head");
};
var setup = window.plugin.favoritePortals.setup;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,111 @@
// ==UserScript==
// @id iitc-plugin-ipas-link@graphracer
// @name IITC Plugin: simulate an attack on portal
// @category Portal Info
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/xosofox/IPAS
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Adds a link to the portal details to open the portal in IPAS - Ingress Portal Attack Simulator on http://ipas.graphracer.com
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.ipasLink = function() {};
window.plugin.ipasLink.setupCallback = function() {
addHook('portalDetailsUpdated', window.plugin.ipasLink.addLink);
}
window.plugin.ipasLink.addLink = function(d) {
$('.linkdetails').append('<aside><a href="http://ipas.graphracer.com/index.html#' + window.plugin.ipasLink.getHash(d.portalDetails) + '" target="ipaswindow" title="Use IPAS to simulate an attack on this portal">Simulate attack</a></aside>');
}
window.plugin.ipasLink.getHash = function (d) {
var hashParts = [];
$.each(d.resonatorArray.resonators, function (ind, reso) {
if (reso) {
hashParts.push(reso.level + "," + reso.distanceToPortal + "," + reso.energyTotal);
} else {
hashParts.push("1,20,0");
}
});
var resos = hashParts.join(";");
hashParts = [];
$.each(d.portalV2.linkedModArray, function (ind, mod) {
// s - shields
// h - heat sink
// i - intentionally left in
// t - turret
//
// f - force amp
// m - multi-hack
// l - link-amp
//
var modCodes = {
"RES_SHIELD": "s",
"HEATSINK": "h",
"TURRET": "t",
"FORCE_AMP": "f",
"MULTIHACK": "m",
"LINK_AMPLIFIER": "l"
}
var mc = "0";
if (mod) {
if (mod.type in modCodes) {
mc = modCodes[mod.type] + mod.rarity.charAt(0).toLowerCase();
//special for shields to distinguish old/new mitigation
if (mod.type == "RES_SHIELD") {
mc += mod.stats.MITIGATION;
}
}
}
hashParts.push(mc);
});
var shields = hashParts.join(",");
var linkParts = [];
var edges = d.portalV2.linkedEdges;
var portalL = new L.LatLng(d.locationE6.latE6 / 1E6, d.locationE6.lngE6 / 1E6)
$.each(edges, function (ind, edge) {
//calc distance in m here
var distance = 1; //default to 1m, so a low level portal would support it
//Try to find other portals details
var guid = edge.otherPortalGuid
if (window.portals[guid] !== undefined) {
//get other portals details as o
var o = window.portals[guid].options.details;
var otherPortalL = new L.LatLng(o.locationE6.latE6 / 1E6, o.locationE6.lngE6 / 1E6);
var distance = Math.round(portalL.distanceTo(otherPortalL));
}
if (!(edge.isOrigin)) {
distance = distance * -1;
}
linkParts.push(distance);
});
var links = linkParts.join(",");
return resos + "/" + shields + "/" + links; //changed with IPAS 1.1 to / instead of |
}
var setup = function () {
window.plugin.ipasLink.setupCallback();
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,21 @@
#!/bin/bash
if test -d ../broken
then
for a in *.js
do
if test -f ../$a
then
true
# echo $a already exists in ..
else
echo creating 'deleted' plugin from header of $a
sed -n -e 's/\@category.*/\@category Deleted/' -e 's/\@description .*/\@description PLUGIN CURRENTLY UNAVAILABLE/' -e 'p' -e '/\/UserScript/q' $a > ../$a
fi
done
else
echo error: wrong directory - must be run in plugins/broken
fi

View File

@ -0,0 +1,107 @@
// ==UserScript==
// @id iitc-plugin-players-resonators@rbino
// @name IITC plugin: Player's Resonators
// @version 0.1.5.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] The plugins finds the resonators of a given player. The input is in the sidebar.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
/*********************************************************************************************************
* Changelog:
*
* 0.1.5 Added portal and reso counter and reso details (Thanks BJT)
* 0.1.4 Added focus link in the toolbox. Some renaming. Removed div to use sidebar style.
* 0.1.3 Effective player name (with wrong capitalization) if it finds some reso
* 0.1.2 Made nickname case insensitive
* 0.1.1 Added mouseover for portal location. Dirty hack to not show mousehover when the alert is fired.
* 0.1.0 First public release
*********************************************************************************************************/
// use own namespace for plugin
window.plugin.playersResonators = function() {};
window.plugin.playersResonators.findReso = function(playername) {
var s = "";
var portalSet = {};
var effectiveNick = "";
var portalCounter = 0;
var resoCounter = 0;
// Assuming there can be no agents with same nick with different lower/uppercase
var nickToFind = playername.toLowerCase();
$.each(window.portals, function(ind, portal){
var resoLevels = {};
var r = portal.options.details.resonatorArray.resonators;
$.each(r, function(ind, reso) {
if (!reso) return true;
var nick = getPlayerName(reso.ownerGuid);
if (nick.toLowerCase() === nickToFind){
resoCounter += 1;
if (!effectiveNick) {
effectiveNick = nick;
}
if (reso.level in resoLevels){
resoLevels[reso.level] += 1;
} else {
resoLevels[reso.level] = 1;
}
if (!portalSet.hasOwnProperty(portal.options.guid)){
portalSet[portal.options.guid] = true;
var latlng = [portal.options.details.locationE6.latE6/1E6, portal.options.details.locationE6.lngE6/1E6].join();
var guid = portal.options.guid;
var zoomPortal = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.options.details.locationE6.latE6+'&lngE6='+portal.options.details.locationE6.lngE6+'&z=17&pguid='+guid;
var a = $('<a>',{
"class": 'help',
text: portal.options.details.portalV2.descriptiveText.TITLE,
title: portal.options.details.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: zoomPortal
})[0].outerHTML;
portalCounter += 1;
s += a + ": ";
}
}
});
if (portalSet.hasOwnProperty(portal.options.guid)){
for (var i = 8; i>0; i--){
if (i in resoLevels)
s += resoLevels[i] + "xL" + i + " ";
}
s += "\n";
}
});
if (s) {
// Showing the playername as a "fake" link to avoid the auto-mouseover effect on the first portal
fakeLinkPlayer = '<a href="#" onClick="return false;">' + effectiveNick + '</a>'
s = fakeLinkPlayer + " has " + resoCounter + " resonators on " + portalCounter + " portals:\n\n" + s;
} else {
s = playername + " has no resonators in this range\n";
}
alert(s);
}
var setup = function() {
var content = '<input id="playerReso" placeholder="Type player name to find resonators..." type="text">';
$('#sidebar').append(content);
$('#toolbox').append(' <a onclick=$("#playerReso").focus() title="Find all portals with resonators of a certain player">Player\'s Reso</a>');
$("#playerReso").keypress(function(e) {
if((e.keyCode ? e.keyCode : e.which) !== 13) return;
var data = $(this).val();
window.plugin.playersResonators.findReso(data);
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,171 @@
// ==UserScript==
// @id iitc-plugin-defense@gluckies
// @name IITC plugin: portal defense
// @category Layer
// @version 0.2.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Shows the defense values of every portal (see also "hightlight portals total mitigation" highlighter)
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalDefense = function() {};
window.plugin.portalDefense.MIN_MAP_ZOOM = 15;
window.plugin.portalDefense.DETAIL_MAP_ZOOM = 17;
window.plugin.portalDefense.DisplayEnum = {
OFF : 0,
SIMPLE : 1,
DETAIL : 2
};
window.plugin.portalDefense.regionLayers = {};
// Use portal add and remove event to control render of regions
window.plugin.portalDefense.portalAdded = function(data) {
data.portal.on('add', function() {
plugin.portalDefense.renderAttackRegion(this);
});
data.portal.on('remove', function() {
plugin.portalDefense.removeAttackRegion(this);
});
}
window.plugin.portalDefense.getDisplay = function() {
if (map.getZoom() >= window.plugin.portalDefense.DETAIL_MAP_ZOOM) {
return window.plugin.portalDefense.DisplayEnum.DETAIL;
} else if (map.getZoom() >= window.plugin.portalDefense.MIN_MAP_ZOOM) {
return window.plugin.portalDefense.DisplayEnum.SIMPLE;
}
return window.plugin.portalDefense.DisplayEnum.OFF;
}
window.plugin.portalDefense.renderAttackRegion = function(portal) {
plugin.portalDefense.removeAttackRegion(portal);
if (window.plugin.portalDefense.currentDisplay == window.plugin.portalDefense.DisplayEnum.OFF) return;
plugin.portalDefense.regionLayers[portal.options.guid] = [];
var defense = window.getPortalMitigationDetails(portal.options.details);
if (defense.total) {
var display = defense.total;
if (window.plugin.portalDefense.currentDisplay == window.plugin.portalDefense.DisplayEnum.DETAIL) {
if (defense.shields) {
display += "<br>"+"\u2297"+defense.shields;
}
if(defense.links) {
display += "<br>"+"\u21b1"+defense.links;
}
}
var region = L.marker(portal.getLatLng(), {
icon: L.divIcon({
className: 'plugin-iic-defense',
clickable: false,
iconAnchor: [-10,10],
html: "<div class='defense-label'>"+display+"</div>"
}),
guid: portal.options.guid
});
plugin.portalDefense.regionLayers[portal.options.guid].push(region);
region.addTo(plugin.portalDefense.regionLayerGroup);
}
}
window.plugin.portalDefense.reload = function() {
$.each(window.portals, function(ind, portal) {
// only render mitigation details for portals added to the map
if (portal._map) {
window.plugin.portalDefense.renderAttackRegion(portal)
}
});
}
window.plugin.portalDefense.removeAttackRegion = function(portal) {
var previousLayers = plugin.portalDefense.regionLayers[portal.options.guid];
if (previousLayers) {
for (var i = 0; i < previousLayers.length; i++) {
plugin.portalDefense.regionLayerGroup.removeLayer(previousLayers[i]);
}
delete plugin.portalDefense.regionLayers[portal.options.guid];
}
}
window.plugin.portalDefense.regions = {}
window.plugin.portalDefense.showOrHide = function() {
var ctrl = $('.leaflet-control-layers-selector + span:contains("Portal Defense")').parent();
var display = window.plugin.portalDefense.getDisplay();
if (display != window.plugin.portalDefense.DisplayEnum.OFF) {
// show the layer
if(!window.plugin.portalDefense.regionLayerGroup.hasLayer(window.plugin.portalDefense.defenseLayerGroup)) {
window.plugin.portalDefense.regionLayerGroup.addLayer(window.plugin.portalDefense.defenseLayerGroup);
}
ctrl.removeClass('disabled').attr('title', '');
} else {
// hide the layer
if(window.plugin.portalDefense.regionLayerGroup.hasLayer(window.plugin.portalDefense.defenseLayerGroup)) {
window.plugin.portalDefense.regionLayerGroup.removeLayer(window.plugin.portalDefense.defenseLayerGroup);
}
ctrl.addClass('disabled').attr('title', 'Zoom in to show those.');
}
if (window.plugin.portalDefense.currentDisplay != display) {
window.plugin.portalDefense.currentDisplay = display;
window.plugin.portalDefense.reload()
}
}
var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.portalDefense.reload()">Reload Defense</a>');
$("<style>")
.prop("type", "text/css")
.html(".plugin-iic-defense {\
font-size: 10px;\
color: #FFFFBB;\
font-family: monospace;\
text-align: center;\
text-shadow: 0 0 0.5em black, 0 0 0.5em black, 0 0 0.5em black;\
pointer-events: none;\
-webkit-text-size-adjust:none;\
}\
.defense-label {\
position:relative;\
background-color:#1B3E59;\
opacity:.6;\
border:0.5px solid #FFCE00;\
width:22px;\
text-align:center;\
color:#FFFFFF;\
text-align:center;\
border-radius:6px;\
}")
.appendTo("head");
window.plugin.portalDefense.currentDisplay = window.plugin.portalDefense.getDisplay();
map.on('zoomend', window.plugin.portalDefense.showOrHide);
// this layer is added to the layer chooser, to be toggled on/off
window.plugin.portalDefense.regionLayerGroup = new L.LayerGroup();
// this layer is added into the above layer, and removed from it when we zoom out too far
window.plugin.portalDefense.defenseLayerGroup = new L.LayerGroup();
window.plugin.portalDefense.regionLayerGroup.addLayer(window.plugin.portalDefense.defenseLayerGroup);
window.addLayerGroup('Portal Defense', window.plugin.portalDefense.regionLayerGroup, true);
window.addHook('portalAdded', window.plugin.portalDefense.portalAdded);
window.plugin.portalDefense.showOrHide();
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,49 @@
// ==UserScript==
// @id iitc-plugin-highlight-bad-deployment-distance@cathesaurus
// @name IITC plugin: highlight badly-deployed portals
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show the effective resonator deployment range, where that average is less than 36 metres
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterBadDeploymentDistance = function() {};
window.plugin.portalHighlighterBadDeploymentDistance.highlight = function(data) {
var d = data.portal.options.details;
var portal_deployment = 0;
if(getTeam(d) !== 0) {
var avgDist = window.getAvgResoDist(d);
if(avgDist > 0 && avgDist < window.HACK_RANGE*0.9) {
portal_deployment = (window.HACK_RANGE - avgDist)/window.HACK_RANGE;
}
if(portal_deployment > 0) {
var fill_opacity = portal_deployment*.85 + .15;
// magenta for *exceptionally* close deployments (spoofing? under 1m average), then shades of
// red, orange and yellow for further out
color = avgDist < 1 ? 'magenta' : avgDist < (window.HACK_RANGE*.25) ? 'red' : avgDist < (window.HACK_RANGE*.6) ? 'orange' : 'yellow';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
}
var setup = function() {
window.addPortalHighlighter('Bad Deployment Distance', window.plugin.portalHighlighterBadDeploymentDistance.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,74 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-upgrade@vita10gy
// @name IITC plugin: highlight portals you can upgrade to a specific level
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to highlight portals you can upgrade to a specific level.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalsCanMakeLevel = function() {};
window.plugin.portalHighligherPortalsCanMakeLevel.highlight = function(data,highlight_level) {
var d = data.portal.options.details;
var current_level = Math.floor(getPortalLevel(d));
var potential_level = Math.floor(window.potentialPortalLevel(d));
var opacity = .7;
if( potential_level > current_level && potential_level === highlight_level) {
color = 'red';
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
//determines the level of poral a user can make all on their own
window.plugin.portalHighligherPortalsCanMakeLevel.playerCanSoloLevel = function(lvl) {
var resonators_total = 0;
var resonators_placed = 0;
var resonator_level = PLAYER.level
while(resonators_placed < 8) {
for(var i = 0; i<MAX_RESO_PER_PLAYER[resonator_level]; i++) {
if(resonators_placed < 8) {
resonators_total += resonator_level;
resonators_placed++;
}
}
resonator_level--;
}
return(Math.floor(resonators_total/8));
}
window.plugin.portalHighligherPortalsCanMakeLevel.getHighlighter = function(lvl) {
return(function(data){
window.plugin.portalHighligherPortalsCanMakeLevel.highlight(data,lvl);
});
}
var setup = function() {
// This is the maximum level of a portal a user can be the "last piece of"
// yes, even a level 1 can be the difference in bumping a portal up to level 7
var max_can_complete = 7;
if(PLAYER.level === 8) {
max_can_complete = 8;
}
// The rational behind the "minimum" level below is that showing a level 7 player, for example, all the portals they can make
// a level 5 would be silly, as they can make ANY portal a level 5.
for(var ptl_lvl = window.plugin.portalHighligherPortalsCanMakeLevel.playerCanSoloLevel()+1; ptl_lvl<=max_can_complete; ptl_lvl++) {
window.addPortalHighlighter('Can Make Level ' + ptl_lvl, window.plugin.portalHighligherPortalsCanMakeLevel.getHighlighter(ptl_lvl));
}
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,64 @@
// ==UserScript==
// @id iitc-plugin-highlight-imminent-decay@cathesaurus
// @name IITC plugin: highlight portals with resonators about to decay
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show resonators due to decay within the next day. Red = portal will decay completely, orange = portal will drop all links, yellow = one or more resonators will decay completely.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterImminentDecay = function() {};
window.plugin.portalHighlighterImminentDecay.highlight = function(data) {
var d = data.portal.options.details;
if(getTeam(d) !== 0) {
//Check the energy of every resonator.
var resImminentDecayCount = 0;
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null) {
var level = parseInt(reso.level);
var maxResonatorEnergy = window.RESO_NRG[level];
var currentResonatorEnergy = parseInt(reso.energyTotal);
if((currentResonatorEnergy / maxResonatorEnergy) < 0.15) {
resImminentDecayCount++;
}
resCount++;
}
});
if(resImminentDecayCount > 0) {
if(resImminentDecayCount === resCount) {
var color = 'red';
} else if((resCount - resImminentDecayCount) < 3) {
color = 'orange';
} else {
color = 'yellow';
}
// Apply colour to portal.
var params = {fillColor: color, fillOpacity: 1};
data.portal.setStyle(params);
}
}
window.COLOR_SELECTED_PORTAL = '#f0f';
}
var setup = function() {
window.addPortalHighlighter('Imminent Decay', window.plugin.portalHighlighterImminentDecay.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,48 @@
// ==UserScript==
// @id iitc-plugin-highlight-mitigation@jonatkins
// @name IITC plugin: hightlight portals total mitigation
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show mitigation. Shades of red to the maximum of 95, then tints towards purple for over 95
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMitigation = function() {};
window.plugin.portalHighligherMitigation.highlight = function(data) {
var defense = window.getPortalMitigationDetails(data.portal.options.details);
if (defense.total > 0) {
var fill_opacity = (defense.total/95)*.85 + .15;
var blue = Math.max(0,Math.min(255,Math.round(defense.excess/80*255)));
var colour = 'rgb(255,0,'+blue+')';
var params = {fillColor: colour, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
var setup = function() {
window.addPortalHighlighter('Mitigation (defense)', window.plugin.portalHighligherMitigation.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,103 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-mods@vita10gy
// @name IITC plugin: highlight portal mods
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote if the portal has the selected mod.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMods = function() {};
window.plugin.portalHighligherMods.highlight = function(data, mod_type) {
var d = data.portal.options.details;
if(!jQuery.isArray(mod_type)) {
mod_type = [mod_type];
}
var mod_effect = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null && jQuery.inArray(mod.type, mod_type) > -1) {
switch(mod.rarity){
case 'COMMON':
mod_effect++;
break;
case 'RARE':
mod_effect+=2;
break;
case 'VERY_RARE':
mod_effect+=3;
break;
}
}
});
if(mod_effect > 0) {
var fill_opacity = mod_effect/12*.8 + .2;
var color = 'red';
fill_opacity = Math.round(fill_opacity*100)/100;
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
window.plugin.portalHighligherMods.highlightNoMods = function(data) {
var d = data.portal.options.details;
var mods = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null) {
mods += 1;
}
});
if(mods == 0) {
var fill_opacity = .6;
var color = 'red';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
} else if(mods <4) {
var fill_opacity = .6;
var color = 'yellow';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
window.plugin.portalHighligherMods.getHighlighter = function(type) {
return(function(data){
window.plugin.portalHighligherMods.highlight(data,type);
});
}
var setup = function() {
$.each(MOD_TYPE, function(ind, name){
window.addPortalHighlighter('Mod: '+name, window.plugin.portalHighligherMods.getHighlighter(ind));
});
window.addPortalHighlighter('Mod: Hackability', window.plugin.portalHighligherMods.getHighlighter(['MULTIHACK', 'HEATSINK']));
window.addPortalHighlighter('Mod: Attack', window.plugin.portalHighligherMods.getHighlighter(['FORCE_AMP', 'TURRET']));
window.addPortalHighlighter('Mod: Defense', window.plugin.portalHighligherMods.getHighlighter(['RES_SHIELD', 'FORCE_AMP', 'TURRET']));
window.addPortalHighlighter('Mod: None', window.plugin.portalHighligherMods.highlightNoMods);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,53 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-my-8-portals@vita10gy
// @name IITC plugin: highlight my level 8's on portals
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote portals you have a level 8 on.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMy8sOnPortals = function() {};
window.plugin.portalHighligherMy8sOnPortals.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
var color = 'red';
var opacity = .7;
var resCount = false;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null && reso.ownerGuid === PLAYER.guid && reso.level == 8) {
resCount = true;
}
});
if(resCount) {
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
}
var setup = function() {
//Don't list it if it isn't applicable yet
if(PLAYER.level == 8) {
window.addPortalHighlighter('My Level 8 Resonators', window.plugin.portalHighligherMy8sOnPortals.highlight);
}
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,70 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-my-portals@vita10gy
// @name IITC plugin: highlight my portals
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote portals you have a hand in. Orange is just ownership. Yellow is shields. Red is Resonators. Red trumps both, yellow trumps orange.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMyPortals = function() {};
window.plugin.portalHighligherMyPortals.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
var color = '';
var opacity = .7;
if(PLAYER.guid === d.captured.capturingPlayerId) {
color = 'orange';
}
var modCount = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null && mod.installingUser === PLAYER.guid) {
color = 'yellow';
modCount++;
}
});
if(modCount > 0) {
opacity = modCount*.25*.7 + .3;
}
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null && reso.ownerGuid === PLAYER.guid) {
color = 'red';
resCount++;
}
});
if(resCount > 0) {
opacity = resCount*.125*.7 + .3;
}
if(color !== '') {
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
}
var setup = function() {
window.addPortalHighlighter('My Portals', window.plugin.portalHighligherMyPortals.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,63 @@
// ==UserScript==
// @id iitc-plugin-highlight-outbound-link-counter@cathesaurus
// @name IITC plugin: highlight portals running low on outbound links
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show the number of outbound links: red = 8 (i.e. no more outbound links may be made), orange = 6 or 7, yellow = 4 or 5.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterOutboundLinkCounter = function() {};
window.plugin.portalHighlighterOutboundLinkCounter.highlight = function(data) {
var d = data.portal.options.details;
var outgoing = 0;
var playerFaction = 0;
if (window.PLAYER.team === 'RESISTANCE') {
playerFaction = window.TEAM_RES;
} else {
playerFaction = window.TEAM_ENL;
}
// Only interested in portals of player's faction
if(getTeam(d) === playerFaction) {
if(d.portalV2.linkedEdges) $.each(d.portalV2.linkedEdges, function(ind, link) {
if (link.isOrigin) {
outgoing++;
}
});
if(outgoing > 3) {
if(outgoing < 6) {
color = 'yellow';
} else if(outgoing < 8) {
color = 'orange';
} else {
color = 'red';
}
var params = {fillColor: color, fillOpacity: 1};
data.portal.setStyle(params);
}
}
}
var setup = function() {
window.addPortalHighlighter('Outbound Links', window.plugin.portalHighlighterOutboundLinkCounter.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,104 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap-by-energy-relative@vita10gy
// @name IITC plugin: highlight portals by ap/energy (relative)
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP/Energy value relative to what's currently on the screen. Brighter is better. Orange means your standard 8 down 8 up swap.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAPPerEnergyRelative = function() {};
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = null;
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = null;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAPPerEnergyRelative.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAPPerEnergyRelative.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP == null ||
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP == null) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.calculateAPLevels();
}
var minApE = window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP;
var maxApE = window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP;
if(PLAYER.team !== d.controllingTeam.team) {
var ap = getAttackApGain(d);
var energy = getCurrentPortalEnergy(d);
if(energy < 1) {
energy = 1;
}
portal_ap = ap.enemyAp;
var opacity = 1;
if(minApE !== maxApE) {
opacity = ((ap.enemyAp / energy) - minApE) / (maxApE - minApE);
}
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
window.plugin.portalHighligherPortalAPPerEnergyRelative.resetAPLevels = function() {
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = null;
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = null;
}
window.plugin.portalHighligherPortalAPPerEnergyRelative.calculateAPLevels = function() {
var displayBounds = map.getBounds();
$.each(window.portals, function(qk, portal) {
if(displayBounds.contains(portal.getLatLng())) {
if(PLAYER.team !== portal.options.details.controllingTeam.team) {
var ap = getAttackApGain(portal.options.details);
var energy = getCurrentPortalEnergy(portal.options.details);
if(energy < 1) {
energy = 1;
}
var portal_ap = ap.enemyAp / energy;
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP === null ||
portal_ap < window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = portal_ap;
}
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP === null ||
portal_ap > window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = portal_ap;
}
}
}
});
}
var setup = function() {
window.addPortalHighlighter('AP/Energy (Relative)', window.plugin.portalHighligherPortalAPPerEnergyRelative.highlight);
window.addHook('requestFinished', window.plugin.portalHighligherPortalAPPerEnergyRelative.resetAPLevels);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,99 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap-relative@vita10gy
// @name IITC plugin: highlight portals by ap relative
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP value relative to what's currently on the screen. Brighter is better. Orange means your standard 8 down 8 up swap.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAPRelative = function() {};
window.plugin.portalHighligherPortalAPRelative.minAP = null;
window.plugin.portalHighligherPortalAPRelative.maxAP = null;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAPRelative.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAPRelative.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
if(window.plugin.portalHighligherPortalAPRelative.minAP == null ||
window.plugin.portalHighligherPortalAPRelative.maxAP == null) {
window.plugin.portalHighligherPortalAPRelative.calculateAPLevels();
}
var minAp = window.plugin.portalHighligherPortalAPRelative.minAP;
var maxAp = window.plugin.portalHighligherPortalAPRelative.maxAP;
var ap = getAttackApGain(d);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== d.controllingTeam.team) {
portal_ap = ap.enemyAp;
if(portal_ap === window.plugin.portalHighligherPortalAPRelative.baseSwapAP) {
color = 'orange';
}
}
var opacity = 1;
if(minAp !== maxAp) {
opacity = (portal_ap - minAp) / (maxAp - minAp);
}
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
window.plugin.portalHighligherPortalAPRelative.resetAPLevels = function() {
window.plugin.portalHighligherPortalAPRelative.minAP = null;
window.plugin.portalHighligherPortalAPRelative.maxAP = null;
}
window.plugin.portalHighligherPortalAPRelative.calculateAPLevels = function() {
var displayBounds = map.getBounds();
$.each(window.portals, function(qk, portal) {
if(displayBounds.contains(portal.getLatLng())) {
var ap = getAttackApGain(portal.options.details);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== portal.options.details.controllingTeam.team) {
portal_ap = ap.enemyAp;
}
if(window.plugin.portalHighligherPortalAPRelative.minAP === null ||
portal_ap < window.plugin.portalHighligherPortalAPRelative.minAP) {
window.plugin.portalHighligherPortalAPRelative.minAP = portal_ap;
}
if(window.plugin.portalHighligherPortalAPRelative.maxAP === null ||
portal_ap > window.plugin.portalHighligherPortalAPRelative.maxAP) {
window.plugin.portalHighligherPortalAPRelative.maxAP = portal_ap;
}
}
});
}
var setup = function() {
window.addPortalHighlighter('AP (Relative)', window.plugin.portalHighligherPortalAPRelative.highlight);
window.addHook('requestFinished', window.plugin.portalHighligherPortalAPRelative.resetAPLevels);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,60 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap@vita10gy
// @name IITC plugin: highlight portals by ap
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP value. Brighter is better. Orange means your standard 8 down 8 up swap.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAP = function() {};
window.plugin.portalHighligherPortalAP.minAP = 65;
//Anything over max AP will be 100% opacity.
window.plugin.portalHighligherPortalAP.maxAP = 6000;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAP.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAP.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
var ap = getAttackApGain(d);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== d.controllingTeam.team) {
portal_ap = ap.enemyAp;
if(portal_ap === window.plugin.portalHighligherPortalAP.baseSwapAP) {
color = 'orange';
}
}
var opacity = (portal_ap - window.plugin.portalHighligherPortalAP.minAP) / window.plugin.portalHighligherPortalAP.maxAP;
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
var setup = function() {
window.addPortalHighlighter('AP (Static)', window.plugin.portalHighligherPortalAP.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,80 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-upgrade@vita10gy
// @name IITC plugin: highlight portals you can upgrade
// @category Highlighter
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Upgradable - Yellow: you can upgrade it at all. Orange: you can change the level. Red: you can make it your level or higher. To Elite: Yellow - To Level 6. Orange - To Level 7. Red - To Level 8.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalsUpgrade = function() {};
window.plugin.portalHighligherPortalsUpgrade.highlight = function(data) {
var d = data.portal.options.details;
var current_level = getPortalLevel(d);
var potential_level = window.potentialPortalLevel(d);
var player_level = PLAYER.level;
var opacity = .7;
if( potential_level > current_level) {
potential_level = Math.floor(potential_level);
current_level = Math.floor(current_level);
//console.log(potential_level + '>' + current_level);
var color = 'yellow';
if(potential_level > current_level) {
color = 'orange';
if(potential_level >= player_level) {
color = 'red';
}
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
window.plugin.portalHighligherPortalsUpgrade.highlight_elite = function(data) {
var d = data.portal.options.details;
var current_level = getPortalLevel(d);
var potential_level = window.potentialPortalLevel(d);
var opacity = .8;
var color = '';
potential_level = Math.floor(potential_level);
current_level = Math.floor(current_level);
if( potential_level > current_level && potential_level >= 6) {
switch(potential_level) {
case 6:
color = 'yellow';
break;
case 7:
color = 'orange';
break;
case 8:
color = 'red';
opacity = .9;
break;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
var setup = function() {
window.addPortalHighlighter('Upgradable', window.plugin.portalHighligherPortalsUpgrade.highlight);
window.addPortalHighlighter('Upgradable to Elite', window.plugin.portalHighligherPortalsUpgrade.highlight_elite);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,54 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-with-L8-resonators@superd
// @name IITC plugin: highlight portals with L8 resonators
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill red of the portals, if portal has L8 res
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalsWithL8Resonators = function() {};
window.plugin.portalsWithL8Resonators.highlight = function(data) {
var d = data.portal.options.details;
var has_L8 = 0;
if(getTeam(d) !== 0) {
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso) {
var level = parseInt(reso.level);
if(level == 8)
{
has_L8+=1;
}
}
});
}
if(has_L8 > 0)
{
var color = 'red';
var opa = has_L8 * 0.125;
var params = {fillColor: color, fillOpacity: opa};
data.portal.setStyle(params);
}
}
var setup = function() {
window.addPortalHighlighter('Portals with L8 Resonators', window.plugin.portalsWithL8Resonators.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,453 @@
// ==UserScript==
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @category Info
// @version 0.0.18.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Display a sortable list of all visible portals with full details about the team, resonators, shields, etc.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
/* whatsnew
* 0.0.15: Add 'age' column to display how long each portal has been controlled by its current owner.
* 0.0.14: Add support to new mods (S:Shield - T:Turret - LA:Link Amp - H:Heat-sink - M:Multi-hack - FA:Force Amp)
* 0.0.12: Use dialog() instead of alert so the user can drag the box around
* 0.0.11: Add nominal energy column and # links, fix sort bug when opened even amounts of times, nits
* 0.0.10: Fixed persistent css problem with alert
* 0.0.9 : bugs hunt
* 0.0.8 : Aborted to avoid problems with Niantic (export portals informations as csv or kml file)
* 0.0.7 : more informations available via tooltips (who deployed, energy, ...), new E/AP column
* 0.0.6 : Add power charge information into a new column + bugfix
* 0.0.5 : Filter portals by clicking on 'All portals', 'Res Portals' or 'Enl Portals'
* 0.0.4 : Add link to portals name, one click to display full information in portal panel, double click to zoom on portal, hover to show address
* 0.0.3 : sorting ascending/descending and add numbers of portals by faction on top on table
* 0.0.2 : add sorting feature when click on header column
* 0.0.1 : initial release, show list of portals with level, team, resonators and shield information
*
* Display code inspired from @vita10gy's scoreboard plugin : iitc-plugin-scoreboard@vita10gy - https://github.com/breunigs/ingress-intel-total-conversion
* Portal link code from xelio - iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
*
* todo : export as GPX, Open in Google Maps, more statistics in the header, what else ?
*/
// use own namespace for plugin
window.plugin.portalslist = function() {};
window.plugin.portalslist.listPortals = []; // structure : name, team, level, resonators = Array, Shields = Array, APgain, Age
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
window.plugin.portalslist.filter=0;
//fill the listPortals array with portals avaliable on the map (level filtered portals will not appear in the table)
window.plugin.portalslist.getPortals = function() {
//filter : 0 = All, 1 = Res, 2 = Enl
//console.log('** getPortals');
var retval=false;
var displayBounds = map.getBounds();
window.plugin.portalslist.listPortals = [];
//get portals informations from IITC
$.each(window.portals, function(i, portal) {
// eliminate offscreen portals (selected, and in padding)
if(!displayBounds.contains(portal.getLatLng())) return true;
retval=true;
var d = portal.options.details;
var name = d.portalV2.descriptiveText.TITLE;
var address = d.portalV2.descriptiveText.ADDRESS;
var img = getPortalImageUrl(d);
var team = portal.options.team;
var now = new Date();
var now_ms = now.getTime();// + (now.getTimezoneOffset() * 60000);
var age_in_seconds = 0;
var age_string_long = 'This portal is not captured.';
var age_string_short = 'n/a';
if(portal.options.details.hasOwnProperty('captured') && portal.options.details.captured.hasOwnProperty('capturedTime')) {
var age_in_seconds = Math.floor((now_ms - portal.options.details.captured.capturedTime)/1000);
var age_string_long = window.plugin.portalslist.secondsToString(age_in_seconds, 'l');
var age_string_short = window.plugin.portalslist.secondsToString(age_in_seconds, 's');
}
switch (team){
case 1 :
window.plugin.portalslist.resP++;
break;
case 2 :
window.plugin.portalslist.enlP++;
break;
}
var level = getPortalLevel(d).toFixed(2);
var guid = portal.options.guid;
//get resonators informations
var resonators = []; // my local resonator array : reso level, reso deployed by, distance to portal, energy total, max
var energy = 0;
var maxenergy=0;
$.each(portal.options.details.resonatorArray.resonators, function(ind, reso) {
if(reso) {
resonators[ind] = [reso.level, window.getPlayerName(reso.ownerGuid), reso.distanceToPortal, reso.energyTotal, RESO_NRG[reso.level]];
energy += reso.energyTotal;
maxenergy += RESO_NRG[reso.level];
} else { resonators[ind] = [0,'',0,0,0]; }
});
// Sort resonators array by resonator level
resonators.sort(function (a, b) {return b[0] - a[0]});
//get mods informations
var mods = [];
$.each(d.portalV2.linkedModArray, function(ind, mod) {
var modShortName='';
if (mod) {
switch (mod.displayName) {
case 'Portal Shield':
modShortName = 'S';
break;
case 'Force Amp':
modShortName = 'FA';
break;
case 'Link Amp':
modShortName = 'LA';
break;
case 'Heat Sink':
modShortName = 'H';
break;
case 'Multi-hack':
modShortName = 'M';
break;
case 'Turret':
modShortName = 'T';
break;
default:
modShortName = '';
break;
}
if (modShortName === '') {
mods[ind] = ['', '', ''];
} else {
if ((modShortName === 'S') &&
((mod.rarity=='COMMON' && mod.stats.MITIGATION == 6) ||
(mod.rarity=='RARE' && mod.stats.MITIGATION == 8) ||
(mod.rarity=='VERY_RARE' && mod.stats.MITIGATION == 10)))
modShortName=modShortName+'!';
mods[ind] = [mod.rarity, getPlayerName(mod.installingUser), modShortName, mod.displayName];
}
}else { mods[ind] = ['', '', '']; }
});
var APgain= getAttackApGain(d).enemyAp;
var thisPortal = {'portal': d,
'name': name,
'team': team,
'level': level,
'guid': guid,
'resonators': resonators,
'energyratio': maxenergy ? Math.floor(energy/maxenergy*100) : 0,
'mods': mods,
'APgain': APgain,
'EAP': (energy/APgain).toFixed(2),
'energy': energy,
'maxenergy': maxenergy,
'links': d.portalV2.linkedEdges.length,
'lat': portal._latlng.lat,
'lng': portal._latlng.lng,
'address': address,
'img': img,
'age': age_in_seconds,
'age_string_long': age_string_long,
'age_string_short': age_string_short};
window.plugin.portalslist.listPortals.push(thisPortal);
});
return retval;
}
window.plugin.portalslist.displayPL = function() {
// debug tools
//var start = new Date().getTime();
//console.log('***** Start ' + start);
var html = '';
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
if (window.plugin.portalslist.getPortals()) {
html += window.plugin.portalslist.portalTable('level', window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter);
} else {
html = '<table><tr><td>Nothing to show!</td></tr></table>';
};
dialog({
html: '<div id="portalslist">' + html + '</div>',
dialogClass: 'ui-dialog-portalslist',
title: 'Portal list: ' + window.plugin.portalslist.listPortals.length + ' ' + (window.plugin.portalslist.listPortals.length == 1 ? 'portal' : 'portals'),
id: 'portal-list',
width: 800
});
//run the name resolving process
resolvePlayerNames();
//debug tools
//end = new Date().getTime();
//console.log('***** end : ' + end + ' and Elapse : ' + (end - start));
}
window.plugin.portalslist.portalTable = function(sortBy, sortOrder, filter) {
// sortOrder <0 ==> desc, >0 ==> asc, i use sortOrder * -1 to change the state
window.plugin.portalslist.filter=filter;
var portals=window.plugin.portalslist.listPortals;
//Array sort
window.plugin.portalslist.listPortals.sort(function(a, b) {
var retVal = 0;
switch (sortBy) {
case 'names':
retVal = a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
break;
case 'r1':
retVal = b.resonators[0][0] - a.resonators[0][0];
if (retVal)
break;
case 'r2':
retVal = b.resonators[1][0] - a.resonators[1][0];
if (retVal)
break;
case 'r3':
retVal = b.resonators[2][0] - a.resonators[2][0];
if (retVal)
break;
case 'r4':
retVal = b.resonators[3][0] - a.resonators[3][0];
if (retVal)
break;
case 'r5':
retVal = b.resonators[4][0] - a.resonators[4][0];
if (retVal)
break;
case 'r6':
retVal = b.resonators[5][0] - a.resonators[5][0];
if (retVal)
break;
case 'r7':
retVal = b.resonators[6][0] - a.resonators[6][0];
if (retVal)
break;
case 'r8':
retVal = b.resonators[7][0] - a.resonators[7][0];
break;
case 's1':
retVal = a.mods[0][2] > b.mods[0][2] ? -1 : 1;
break;
case 's2':
retVal = a.mods[1][2] > b.mods[1][2] ? -1 : 1;
break;
case 's3':
retVal = a.mods[2][2] > b.mods[2][2] ? -1 : 1;
break;
case 's4':
retVal = a.mods[3][2] > b.mods[3][2] ? -1 : 1;
break;
default:
retVal = b[sortBy] - a[sortBy];
break;
}
if (sortOrder > 0) retVal = -retVal; //thx @jonatkins
return retVal;
});
var sort = window.plugin.portalslist.portalTableSort;
var html = window.plugin.portalslist.stats();
html += '<table>'
+ '<tr><th ' + sort('names', sortBy, -1) + '>Portal</th>'
+ '<th ' + sort('level', sortBy, -1) + '>Level</th>'
+ '<th title="Team" ' + sort('team', sortBy, -1) + '>T</th>'
+ '<th ' + sort('r1', sortBy, -1) + '>R1</th>'
+ '<th ' + sort('r2', sortBy, -1) + '>R2</th>'
+ '<th ' + sort('r3', sortBy, -1) + '>R3</th>'
+ '<th ' + sort('r4', sortBy, -1) + '>R4</th>'
+ '<th ' + sort('r5', sortBy, -1) + '>R5</th>'
+ '<th ' + sort('r6', sortBy, -1) + '>R6</th>'
+ '<th ' + sort('r7', sortBy, -1) + '>R7</th>'
+ '<th ' + sort('r8', sortBy, -1) + '>R8</th>'
+ '<th ' + sort('energy', sortBy, -1) + '>Energy</th>'
+ '<th ' + sort('energyratio', sortBy, -1) + '>%</th>'
+ '<th ' + sort('links', sortBy, -1) + '>Links</th>'
+ '<th ' + sort('s1', sortBy, -1) + '>M1</th>'
+ '<th ' + sort('s2', sortBy, -1) + '>M2</th>'
+ '<th ' + sort('s3', sortBy, -1) + '>M3</th>'
+ '<th ' + sort('s4', sortBy, -1) + '>M4</th>'
+ '<th ' + sort('mitigation', sortBy, -1) + '>Mit.</th>'
+ '<th ' + sort('APgain', sortBy, -1) + '>AP Gain</th>'
+ '<th title="Energy / AP Gain ratio" ' + sort('EAP', sortBy, -1) + '>E/AP</th>'
+ '<th ' + sort('age', sortBy, -1) + '>Age</th></tr>';
$.each(portals, function(ind, portal) {
if (filter === 0 || filter === portal.team) {
html += '<tr class="' + (portal.team === 1 ? 'res' : (portal.team === 2 ? 'enl' : 'neutral')) + '">'
+ '<td style="">' + window.plugin.portalslist.getPortalLink(portal.portal, portal.guid) + '</td>'
+ '<td class="L' + Math.floor(portal.level) +'">' + portal.level + '</td>'
+ '<td style="text-align:center;">' + portal.team + '</td>';
var mitigationDetails = getPortalMitigationDetails(portal.portal);
portal.mitigation = mitigationDetails.total + mitigationDetails.excess;
var title;
var percent;
$.each([0, 1, 2, 3 ,4 ,5 ,6 ,7], function(ind, slot) {
percent = portal.resonators[slot][4] ? Math.floor(portal.resonators[slot][3]/portal.resonators[slot][4]*100) : 0;
title = 'title="owner: <b>' + portal.resonators[slot][1] + '</b><br>'
+ 'energy: ' + portal.resonators[slot][3] + ' / ' + portal.resonators[slot][4] + ' (' + percent + '%)<br>'
+ 'distance: ' + portal.resonators[slot][2] + 'm';
html += '<td class="L' + portal.resonators[slot][0] +'" ' + title + '">' + portal.resonators[slot][0] + '</td>';
});
html += '<td style="cursor:help" title="'+ portal.energy +'">' + prettyEnergy(portal.energy) + '</td>'
+ '<td style="cursor:help" title="' + portal.energy + ' / ' + portal.maxenergy +'">' + portal.energyratio + '%</td>'
+ '<td style="cursor:help" title="' + portal.links + '">' + portal.links + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[0][0]]+';" title="Mod : ' + portal.mods[0][3] + '\nInstalled by : ' + portal.mods[0][1] + '\nRarity : ' + portal.mods[0][0] + '">' + portal.mods[0][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[1][0]]+';" title="Mod : ' + portal.mods[1][3] + '\nInstalled by : ' + portal.mods[1][1] + '\nRarity : ' + portal.mods[1][0] + '">' + portal.mods[1][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[2][0]]+';" title="Mod : ' + portal.mods[2][3] + '\nInstalled by : ' + portal.mods[2][1] + '\nRarity : ' + portal.mods[2][0] + '">' + portal.mods[2][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[3][0]]+';" title="Mod : ' + portal.mods[3][3] + '\nInstalled by : ' + portal.mods[3][1] + '\nRarity : ' + portal.mods[3][0] + '">' + portal.mods[3][2] + '</td>'
+ '<td>' + portal.mitigation + '</td>'
+ '<td>' + portal.APgain + '</td>'
+ '<td>' + portal.EAP + '</td>'
+ '<td style="cursor:help;" title="' + portal.age_string_long + '">' + portal.age_string_short + '</td>';
html+= '</tr>';
}
});
html += '</table>';
html += '<div class="disclaimer">Click on portals table headers to sort by that column. '
+ 'Click on <b>All Portals, Resistance Portals, Enlightened Portals</b> to filter<br>'
+ 'Thanks to @vita10gy & @xelio for their IITC plugins who inspired me. A <a href="https://plus.google.com/113965246471577467739">@teo96</a> production. Vive la Résistance !</div>';
window.plugin.portalslist.sortOrder = window.plugin.portalslist.sortOrder*-1;
return html;
}
window.plugin.portalslist.stats = function(sortBy) {
//console.log('** stats');
var html = '<table><tr>'
+ '<td class="filterAll" style="cursor:pointer" onclick="window.plugin.portalslist.portalTable(\'level\',-1,0)"><a href=""></a>All Portals : (click to filter)</td><td class="filterAll">' + window.plugin.portalslist.listPortals.length + '</td>'
+ '<td class="filterRes" style="cursor:pointer" class="sorted" onclick="window.plugin.portalslist.portalTable(\'level\',-1,1)">Resistance Portals : </td><td class="filterRes">' + window.plugin.portalslist.resP +' (' + Math.floor(window.plugin.portalslist.resP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '<td class="filterEnl" style="cursor:pointer" class="sorted" onclick="window.plugin.portalslist.portalTable(\'level\',-1,2)">Enlightened Portals : </td><td class="filterEnl">'+ window.plugin.portalslist.enlP +' (' + Math.floor(window.plugin.portalslist.enlP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '</tr>'
+ '</table>';
return html;
}
// A little helper function so the above isn't so messy
window.plugin.portalslist.portalTableSort = function(name, by) {
var retVal = 'data-sort="' + name + '"';
if(name === by) {
retVal += ' class="sorted"';
}
return retVal;
};
// portal link - single click: select portal
// double click: zoom to and select portal
// hover: show address
// code from getPortalLink function by xelio from iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
window.plugin.portalslist.getPortalLink = function(portal,guid) {
var latlng = [portal.locationE6.latE6/1E6, portal.locationE6.lngE6/1E6].join();
var jsSingleClick = 'window.renderPortalDetails(\''+guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.locationE6.latE6+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+guid;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('<a>',{
"class": 'help',
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
var div = '<div class="portalTitle">'+a+'</div>';
return div;
}
// length can be "s" or "l" for "short" or "long"
window.plugin.portalslist.secondsToString = function(seconds, length) {
var numdays = Math.floor(seconds / 86400);
var numhours = Math.floor((seconds % 86400) / 3600);
var numminutes = Math.floor(((seconds % 86400) % 3600) / 60);
var numseconds = ((seconds % 86400) % 3600) % 60;
if(length === "l") {
return numdays + " days " + numhours + " hours " + numminutes + " minutes " + numseconds + " seconds";
} else {
return numdays + "d" + numhours + "h";
}
}
var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.portalslist.displayPL()" title="Display a list of portals in the current view">Portals list</a>');
$('head').append('<style>' +
//style.css sets dialog max-width to 700px - override that here
// (the width: 800 parameter to dialog is NOT enough to override that css limit)
'#dialog-portal-list {max-width: 800px !important;}' +
'#portalslist table {margin-top:5px; border-collapse: collapse; empty-cells: show; width:100%; clear: both;}' +
'#portalslist table td, #portalslist table th {border-bottom: 1px solid #0b314e; padding:3px; color:white; background-color:#1b415e}' +
'#portalslist table tr.res td { background-color: #005684; }' +
'#portalslist table tr.enl td { background-color: #017f01; }' +
'#portalslist table tr.neutral td { background-color: #000000; }' +
'#portalslist table th { text-align: center;}' +
'#portalslist table td { text-align: center;}' +
'#portalslist table td.L0 { cursor: help; background-color: #000000 !important;}' +
'#portalslist table td.L1 { cursor: help; background-color: #FECE5A !important;}' +
'#portalslist table td.L2 { cursor: help; background-color: #FFA630 !important;}' +
'#portalslist table td.L3 { cursor: help; background-color: #FF7315 !important;}' +
'#portalslist table td.L4 { cursor: help; background-color: #E40000 !important;}' +
'#portalslist table td.L5 { cursor: help; background-color: #FD2992 !important;}' +
'#portalslist table td.L6 { cursor: help; background-color: #EB26CD !important;}' +
'#portalslist table td.L7 { cursor: help; background-color: #C124E0 !important;}' +
'#portalslist table td.L8 { cursor: help; background-color: #9627F4 !important;}' +
'#portalslist table td:nth-child(1) { text-align: left;}' +
'#portalslist table th { cursor:pointer; text-align: right;}' +
'#portalslist table th:nth-child(1) { text-align: left;}' +
'#portalslist table th.sorted { color:#FFCE00; }' +
'#portalslist .filterAll { margin-top: 10px;}' +
'#portalslist .filterRes { margin-top: 10px; background-color: #005684 }' +
'#portalslist .filterEnl { margin-top: 10px; background-color: #017f01 }' +
'#portalslist .disclaimer { margin-top: 10px; font-size:10px; }' +
'#portalslist .portalTitle { display: inline-block; width: 160px !important; min-width: 160px !important; max-width: 160px !important; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }' +
'</style>');
// Setup sorting
$(document).on('click.portalslist', '#portalslist table th', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter));
});
$(document).on('click.portalslist', '#portalslist .filterAll', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,0));
});
$(document).on('click.portalslist', '#portalslist .filterRes', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,1));
});
$(document).on('click.portalslist', '#portalslist .filterEnl', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,2));
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -0,0 +1,340 @@
// ==UserScript==
// @id iitc-plugin-scoreboard@vita10gy
// @name IITC plugin: show a localized scoreboard.
// @category Info
// @version 0.1.9.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] A localized scoreboard.
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.scoreboard = function() {};
window.plugin.scoreboard.scores = {};
window.plugin.scoreboard.playerGuids = new Array();
window.plugin.scoreboard.resetTeam = function(team) {
var scores = window.plugin.scoreboard.scores['team'];
scores[team] = {};
scores[team]['mu'] = 0;
scores[team]['count_fields'] = 0;
scores[team]['count_links'] = 0;
scores[team]['count_portals'] = 0;
scores[team]['count_resonators'] = 0;
scores[team]['count_mods'] = 0;
scores[team]['link_length'] = 0;
scores[team]['field_area'] = 0;
scores[team]['largest'] = {};
};
window.plugin.scoreboard.initPlayer = function(player, team) {
var scores = window.plugin.scoreboard.scores['player'];
if(scores[player] === undefined) {
scores[player] = {};
scores[player]['team'] = team;
scores[player]['mu'] = 0;
scores[player]['count_fields'] = 0;
scores[player]['count_links'] = 0;
scores[player]['count_portals'] = 0;
scores[player]['count_resonators'] = 0;
scores[player]['link_length'] = 0;
scores[player]['field_area'] = 0;
scores[player]['count_mods'] = 0;
scores[player]['largest'] = {};
window.plugin.scoreboard.playerGuids.push(player);
}
}
window.plugin.scoreboard.compileStats = function() {
var somethingInView = false;
window.plugin.scoreboard.playerGuids = new Array();
window.plugin.scoreboard.scores = {'team': {}, 'player': {}};
var scores = window.plugin.scoreboard.scores;
window.plugin.scoreboard.resetTeam(TEAM_RES);
window.plugin.scoreboard.resetTeam(TEAM_ENL);
$.each(window.fields, function(qk, val) {
var team = getTeam(val.options.data);
// Google sends fields long since dead in the data. This makes sure it's still actually up.
if(window.portals[val.options.vertices.vertexA.guid] !== undefined ||
window.portals[val.options.vertices.vertexB.guid] !== undefined ||
window.portals[val.options.vertices.vertexC.guid] !== undefined ) {
var fieldArea = window.plugin.scoreboard.fieldArea(val);
somethingInView = true;
scores['team'][team]['count_fields']++;
scores['team'][team]['field_area'] += fieldArea;
val.options.data.fieldArea = fieldArea;
var largestArea = scores['team'][team]['largest']['field_area'];
if(largestArea === undefined || largestArea.options.data.fieldArea < val.options.data.fieldArea) {
largestArea = val;
}
scores['team'][team]['largest']['field_area'] = largestArea;
}
});
$.each(window.links, function(qk, link) {
somethingInView = true;
var team = getTeam(link.options.data);
scores['team'][team]['count_links']++;
var linkLength = window.plugin.scoreboard.portalDistance(link.options.data.edge.destinationPortalLocation,link.options.data.edge.originPortalLocation);
scores['team'][team]['link_length'] += linkLength;
var largestLink = scores['team'][team]['largest']['link'];
if(largestLink === undefined || largestLink.distance < linkLength) {
largestLink = {};
largestLink.distance = linkLength;
}
scores['team'][team]['largest']['link'] = largestLink;
});
$.each(window.portals, function(qk, portal) {
somethingInView = true;
var team = getTeam(portal.options.details);
if(team !== TEAM_NONE) {
var player = portal.options.details.captured.capturingPlayerId;
window.plugin.scoreboard.initPlayer(player, team);
scores['team'][team]['count_portals']++;
scores['player'][player]['count_portals']++;
$.each(portal.options.details.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null) {
window.plugin.scoreboard.initPlayer(mod.installingUser, team);
somethingInView = true;
scores['team'][team]['count_mods']++;
scores['player'][mod.installingUser]['count_mods']++;
}
});
$.each(portal.options.details.resonatorArray.resonators, function(ind, reso) {
if(reso !== null) {
somethingInView = true;
window.plugin.scoreboard.initPlayer(reso.ownerGuid, team);
scores['team'][team]['count_resonators']++;
scores['player'][reso.ownerGuid]['count_resonators']++;
}
});
}
});
return somethingInView;
};
window.plugin.scoreboard.teamTableRow = function(field,title) {
var scores = window.plugin.scoreboard.scores['team'];
var retVal = '<tr><td>'
+ title
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_RES][field]))
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_ENL][field]))
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_RES][field] + scores[TEAM_ENL][field]))
+ '</td></tr>';
return retVal;
};
window.plugin.scoreboard.fieldInfoArea = function(field) {
var title = '';
var retVal = '';
if(field !== undefined) {
var portal = window.portals[field.options.vertices.vertexA.guid];
if(portal !== undefined) {
title = ' @' + portal.options.details.portalV2.descriptiveText.TITLE;
}
retVal = '<div title="' + title + '">'
+ window.digits(Math.round(field.options.data.fieldArea))
+ '</div>';
} else {
retVal = 'N/A';
}
return retVal;
};
window.plugin.scoreboard.playerTableRow = function(playerGuid) {
var scores = window.plugin.scoreboard.scores['player'];
var retVal = '<tr class="'
+ (scores[playerGuid]['team'] === TEAM_RES ? 'res' : 'enl')
+'"><td>'
+ window.getPlayerName(playerGuid);
+ '</td>';
$.each(['count_portals','count_resonators','count_mods'], function(i, field) {
retVal += '<td class="number">'
+ window.digits(Math.round(scores[playerGuid][field]))
+ '</td>';
});
retVal += '</tr>';
return retVal;
};
window.plugin.scoreboard.playerTable = function(sortBy) {
// Sort the playerGuid array by sortBy
window.plugin.scoreboard.playerGuids.sort(function(a, b) {
var playerA = window.plugin.scoreboard.scores['player'][a];
var playerB = window.plugin.scoreboard.scores['player'][b];
var retVal = 0;
if(sortBy === 'names') {
retVal = window.getPlayerName(a).toLowerCase() < window.getPlayerName(b).toLowerCase() ? -1 : 1;
} else {
retVal = playerB[sortBy] - playerA[sortBy];
}
return retVal;
});
var sort = window.plugin.scoreboard.playerTableSort;
var scoreHtml = '<table>'
+ '<tr><th ' + sort('names', sortBy) + '>Player</th>'
+ '<th ' + sort('count_portals', sortBy) + '>Portals</th>'
+ '<th ' + sort('count_resonators', sortBy) + '>Resonators</th>'
+ '<th ' + sort('count_mods', sortBy) + '>Mods</th></tr>';
$.each(window.plugin.scoreboard.playerGuids, function(index, guid) {
scoreHtml += window.plugin.scoreboard.playerTableRow(guid);
});
scoreHtml += '</table>';
return scoreHtml;
}
// A little helper function so the above isn't so messy
window.plugin.scoreboard.playerTableSort = function(name, by) {
var retVal = 'data-sort="' + name + '"';
if(name === by) {
retVal += ' class="sorted"';
}
return retVal;
};
window.plugin.scoreboard.display = function() {
var somethingInView = window.plugin.scoreboard.compileStats();
var scores = window.plugin.scoreboard.scores;
var scoreHtml = '';
var title = '';
if(somethingInView) {
scoreHtml += '<table>'
+ '<tr><th></th><th class="number">Resistance</th><th class="number">Enlightened</th><th class="number">Total</th></tr>'
+ window.plugin.scoreboard.teamTableRow('count_fields','Field #')
+ window.plugin.scoreboard.teamTableRow('field_area','Field (km&sup2;)')
+ window.plugin.scoreboard.teamTableRow('count_links','Link #')
+ window.plugin.scoreboard.teamTableRow('link_length','Link (m)')
+ window.plugin.scoreboard.teamTableRow('count_portals','Portals')
+ window.plugin.scoreboard.teamTableRow('count_resonators','Resonators')
+ window.plugin.scoreboard.teamTableRow('count_mods','Mods')
+ '</table>';
scoreHtml += '<table>'
+ '<tr><th></th><th>Resistance</th><th>Enlightened</th></tr>'
+ '<tr><td>Largest Field (km&sup2;)</td><td>'
+ window.plugin.scoreboard.fieldInfoArea(scores['team'][TEAM_RES]['largest']['field_area'])
+ '</td><td>'
+ window.plugin.scoreboard.fieldInfoArea(scores['team'][TEAM_ENL]['largest']['field_area'])
+ '</td></tr>'
+ '<tr><td>Longest Link (m)</td><td>';
if(scores['team'][TEAM_RES]['largest']['link'] === undefined) {
scoreHtml += 'N/A';
}
else {
scoreHtml += window.digits(Math.round(scores['team'][TEAM_RES]['largest']['link']['distance']));
}
scoreHtml += '</td><td>';
if(scores['team'][TEAM_ENL]['largest']['link'] === undefined) {
scoreHtml += 'N/A';
}
else {
scoreHtml += window.digits(Math.round(scores['team'][TEAM_ENL]['largest']['link']['distance']));
}
scoreHtml += '</td></tr>'
+ '</table>'
+ '<div id="players">'
+ window.plugin.scoreboard.playerTable('count_portals')
+ '</div>';
scoreHtml += '<div class="disclaimer">Click on player table headers to sort by that column. '
+ 'Score is subject to portals available based on zoom level. '
+ 'If names are unresolved try again. For best results wait until updates are fully loaded.</div>';
} else {
scoreHtml += 'You need something in view.';
title = 'nothing in view';
}
dialog({
html: '<div id="scoreboard">' + scoreHtml + '</div>',
title: 'Scoreboard: ' + title,
dialogClass: 'ui-dialog-scoreboard',
id: 'scoreboard'
});
//run the name resolving process
resolvePlayerNames();
}
window.plugin.scoreboard.portalDistance = function(portalAE6Location, portalBE6Location) {
portalA = new L.LatLng(portalAE6Location.latE6 / 1E6, portalAE6Location.lngE6 / 1E6);
portalB = new L.LatLng(portalBE6Location.latE6 / 1E6, portalBE6Location.lngE6 / 1E6);
return (portalA.distanceTo(portalB));
}
window.plugin.scoreboard.fieldArea = function(field) {
var verts = field.options.vertices;
var sideA = window.plugin.scoreboard.portalDistance(verts.vertexA.location,verts.vertexB.location) / 1000;
var sideB = window.plugin.scoreboard.portalDistance(verts.vertexB.location,verts.vertexC.location) / 1000;
var sideC = window.plugin.scoreboard.portalDistance(verts.vertexC.location,verts.vertexA.location) / 1000;
// Heron's Formula;
var perimeter = sideA + sideB + sideC;
var s = perimeter/2;
return Math.sqrt(s*(s-sideA)*(s-sideB)*(s-sideC));
}
var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.scoreboard.display()" title="Display a scoreboard per team for the current view">Scoreboard</a>');
$('head').append('<style>' +
'.ui-dialog-scoreboard {width: auto !important; min-width: 400px !important; max-width: 600px !important;}' +
'#scoreboard table {margin-top:10px; border-collapse: collapse; empty-cells: show; width:100%; clear: both;}' +
'#scoreboard table td, #scoreboard table th {border-bottom: 1px solid #0b314e; padding:3px; color:white; background-color:#1b415e}' +
'#scoreboard table tr.res td { background-color: #005684; }' +
'#scoreboard table tr.enl td { background-color: #017f01; }' +
'#scoreboard table tr:nth-child(even) td { opacity: .8 }' +
'#scoreboard table tr:nth-child(odd) td { color: #ddd !important; }' +
'#scoreboard table th { text-align:left }' +
'#scoreboard table td.number, #scoreboard table th.number { text-align:right }' +
'#players table th { cursor:pointer; text-align: right;}' +
'#players table th:nth-child(1) { text-align: left;}' +
'#scoreboard table th.sorted { color:#FFCE00; }' +
'#scoreboard .disclaimer { margin-top:10px; font-size:10px; }' +
'.mu_score { margin-bottom: 10px; }' +
'.mu_score span { overflow: hidden; padding-top:2px; padding-bottom: 2px; display: block; font-weight: bold; float: left; box-sizing: border-box; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; }' +
'.mu_score span.res { background-color: #005684; text-align: right; padding-right:4px; }' +
'.mu_score span.enl { background-color: #017f01; padding-left: 4px; }' +
'</style>');
// Setup sorting
$(document).on('click', '#players table th', function() {
$('#players').html(window.plugin.scoreboard.playerTable($(this).data('sort')));
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,141 +1,15 @@
// ==UserScript==
// @id iitc-plugin-compute-ap-stats@Hollow011
// @name IITC plugin: Compute AP statistics
// @category Info
// @category Deleted
// @version 0.3.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Displays the per-team AP gains available in the current view.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.compAPStats = function() {};
window.plugin.compAPStats.setupCallback = function() {
// add a new div to the bottom of the sidebar and style it
$('#sidebar').append('<div id="available_ap_display"></div>');
$('#available_ap_display').css({'color':'#ffce00', 'font-size':'90%', 'padding':'4px 2px'});
// do an initial calc for sidebar sizing purposes
window.plugin.compAPStats.onPositionMove();
// make the value update when the map data updates
window.addHook('mapDataRefreshEnd', window.plugin.compAPStats.onPositionMove);
}
window.plugin.compAPStats.onPositionMove = function() {
var result = window.plugin.compAPStats.compAPStats();
$('#available_ap_display').html('Available AP in this area:<table>'
+ '<tr><td>Enlightened:</td><td style="text-align:right">' + digits(result[1]) + '</td></tr>'
+ '<tr><td>Resistance:</td><td style="text-align:right">' + digits(result[0]) + '</td></tr>'
+ '</table>');
}
window.plugin.compAPStats.missingResonatorAP = function(portal) {
var resAP = 0;
var missing_resonators = 0;
$.each(portal.resonatorArray.resonators, function(ind, reso) {
if(reso === null) {
missing_resonators++;
}
});
if(missing_resonators > 0) {
resAP = window.DEPLOY_RESONATOR * missing_resonators;
resAP += window.COMPLETION_BONUS;
}
return(resAP);
};
window.plugin.compAPStats.compAPStats = function() {
var totalAP_RES = 0;
var totalAP_ENL = 0;
var allResEdges = [];
var allResFields = [];
var allEnlEdges = [];
var allEnlFields = [];
var displayBounds = map.getBounds();
// Grab every portal in the viewable area and compute individual AP stats
$.each(window.portals, function(ind, portal) {
var d = portal.options.details;
// eliminate offscreen portals (selected, and in padding)
if(!displayBounds.contains(portal.getLatLng())) return true;
var portalStats = getAttackApGain(d);
var portalSum = portalStats.resoAp + portalStats.captureAp;
if (getTeam(d) === TEAM_ENL) {
totalAP_RES += portalSum;
$.each(d.portalV2.linkedEdges||[], function(ind, edge) {
if(!edge) return true;
allEnlEdges.push(edge.edgeGuid);
});
$.each(d.portalV2.linkedFields||[], function(ind, field) {
if(!field) return true;
allEnlFields.push(field);
});
totalAP_ENL += window.plugin.compAPStats.missingResonatorAP(d);
}
else if (getTeam(d) === TEAM_RES) {
totalAP_ENL += portalSum;
$.each(d.portalV2.linkedEdges||[], function(ind, edge) {
if(!edge) return true;
allResEdges.push(edge.edgeGuid);
});
$.each(d.portalV2.linkedFields||[], function(ind, field) {
if(!field) return true;
allResFields.push(field);
});
totalAP_RES += window.plugin.compAPStats.missingResonatorAP(d);
} else {
// it's a neutral portal, potential for both teams. by definition no fields or edges
totalAP_ENL += portalSum;
totalAP_RES += portalSum;
}
});
// Compute team field AP
allResFields = uniqueArray(allResFields);
totalAP_ENL += (allResFields.length * DESTROY_FIELD);
allEnlFields = uniqueArray(allEnlFields);
totalAP_RES += (allEnlFields.length * DESTROY_FIELD);
// Compute team Link AP
allResEdges = uniqueArray(allResEdges);
totalAP_ENL += (allResEdges.length * DESTROY_LINK);
allEnlEdges = uniqueArray(allEnlEdges);
totalAP_RES += (allEnlEdges.length * DESTROY_LINK);
return [totalAP_RES, totalAP_ENL];
}
var setup = function() {
window.plugin.compAPStats.setupCallback();
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-raw-portal-data
// @name IITC plugin: Debug: Raw portal JSON data
// @category Debug
// @version 0.2.2.@@DATETIMEVERSION@@
// @version 0.2.3.@@DATETIMEVERSION@@
// @namespace rawdata
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -36,40 +36,43 @@ window.plugin.rawdata.showPortalData = function(guid) {
}
var d = window.portals[guid].options.details;
var data = window.portals[guid].options.data;
var ts = window.portals[guid].options.timestamp;
var title = 'Raw portal data: ' + (d.portalV2.descriptiveText.TITLE || '<no title>') + ' ('+guid+')';
var title = 'Raw portal data: ' + (data.title || '<no title>') + ' ('+guid+')';
var body =
'<b>Portal GUID</b>: <code>'+guid+'</code><br />' +
'<b>Entity timestamp</b>: <code>'+ts+'</code> - '+window.unixTimeToDateTimeString(ts,true)+'<br />' +
'<pre>'+JSON.stringify(d,null,2)+'</pre>';
'<pre>'+JSON.stringify(data,null,2)+'</pre>';
var details = portalDetail.get(guid);
if (details) {
body += '<b>Portal details:</b><pre>'+JSON.stringify(details,null,2)+'</pre>';
}
body += '<p><b>Links referencing this portal</b></p>';
var haslinks = false;
for (var lguid in window.links) {
var linkGuids = getPortalLinks(guid);
$.each(linkGuids.in.concat(linkGuids.out), function(i,lguid) {
var l = window.links[lguid];
var ld = l.options.details;
if (ld.edge.originPortalGuid == guid || ld.edge.destinationPortalGuid == guid) {
body += '<b>Link GUID</b>: <code>'+l.options.guid+'</code><br /><pre>'+JSON.stringify(ld,null,2)+'</pre>';
haslinks = true;
}
}
var ld = l.options.data;
body += '<b>Link GUID</b>: <code>'+l.options.guid+'</code><br /><pre>'+JSON.stringify(ld,null,2)+'</pre>';
haslinks = true;
});
if (!haslinks) body += '<p>No links to/from this portal</p>';
body += '<p><b>Fields referencing this portal</b></p>';
var hasfields = false;
for (var fguid in window.fields) {
var fieldGuids = getPortalFields(guid);
$.each(fieldGuids, function(i,fguid) {
var f = window.fields[fguid];
var fd = f.options.details;
if (fd.capturedRegion.vertexA.guid == guid ||
fd.capturedRegion.vertexB.guid == guid ||
fd.capturedRegion.vertexC.guid == guid) {
body += '<b>Field guid</b>: <code>'+f.options.guid+'</code><br /><pre>'+JSON.stringify(fd,null,2)+'</pre>';
hasfields = true;
}
}
var fd = f.options.data;
body += '<b>Field guid</b>: <code>'+f.options.guid+'</code><br /><pre>'+JSON.stringify(fd,null,2)+'</pre>';
hasfields = true;
});
if (!hasfields) body += '<p>No fields linked to this portal</p>';
dialog({

View File

@ -1,811 +1,15 @@
// ==UserScript==
// @id iitc-plugin-draw-resonators@xelio
// @name IITC plugin: Draw resonators
// @category Layer
// @category Deleted
// @version 0.4.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Draw resonators on map. With stylers to highlight resonators with specific criteria.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.drawResonators = function() {};
window.plugin.drawResonators.options;
window.plugin.drawResonators.render;
//////// Render for handling render of resonators ////////
// As long as 'window.Render.prototype.createPortalEntity' delete and recreate portal
// on any change of data, this resonator render should make resonator create and remove
// with portal correctly.
//
// Resonators will create when
// 1.Portal added to map
// 2.Zooming in to enable zoom level
//
// Resonators will remove when
// 1.Portal removed from map
// 2.Zooming out beyond enable zoom level
window.plugin.drawResonators.Render = function(options) {
this.enableZoomLevel = options['enableZoomLevel'];
this.useStyler = '';
this.stylers = {};
this.resonators = {};
this.resonatorLayerGroup = new L.LayerGroup();
this.addStyler(new window.plugin.drawResonators.Styler());
this.beforeZoomLevel = map.getZoom();
this.portalAdded = this.portalAdded.bind(this);
this.createResonatorEntities = this.createResonatorEntities.bind(this);
this.deleteResonatorEntities = this.deleteResonatorEntities.bind(this);
this.handleResonatorEntitiesBeforeZoom = this.handleResonatorEntitiesBeforeZoom.bind(this);
this.handleResonatorEntitiesAfterZoom = this.handleResonatorEntitiesAfterZoom.bind(this);
this.handleEnableZoomLevelChange = this.handleEnableZoomLevelChange.bind(this);
this.portalSelectionChange = this.portalSelectionChange.bind(this);
this.changeStyler = this.changeStyler.bind(this);
this.getStylersList = this.getStylersList.bind(this);
};
window.plugin.drawResonators.Render.prototype.registerHook = function() {
window.addHook('portalAdded', this.portalAdded);
window.addHook('portalSelected', this.portalSelectionChange);
window.map.on('zoomstart', this.handleResonatorEntitiesBeforeZoom);
window.map.on('zoomend', this.handleResonatorEntitiesAfterZoom);
}
window.plugin.drawResonators.Render.prototype.portalAdded = function(data) {
var marker = data.portal;
var render = this;
marker.on('add', function() {
render.createResonatorEntities(this); // the 'this' in here is the portal.
});
marker.on('remove', function() {
render.deleteResonatorEntities(this.options.guid); // the 'this' in here is the portal.
});
}
window.plugin.drawResonators.Render.prototype.createResonatorEntities = function(portal) {
// No need to check for existing resonators, as old resonators should be removed with the portal marker.
if(!this.isResonatorsShow()) return;
var portalDetails = portal.options.details;
var resonatorsWithConnector = new L.LayerGroup()
var portalLatLng = [portalDetails.locationE6.latE6/1E6, portalDetails.locationE6.lngE6/1E6];
var portalSelected = selectedPortal === portal.options.guid;
for(var i in portalDetails.resonatorArray.resonators) {
resoData = portalDetails.resonatorArray.resonators[i];
if(resoData === null) continue;
var resoLatLng = this.getResonatorLatLng(resoData.distanceToPortal, resoData.slot, portalLatLng);
var resoMarker = this.createResoMarker(resoData, resoLatLng, portalSelected);
var connMarker = this.createConnMarker(resoData, resoLatLng, portalLatLng, portalSelected);
resonatorsWithConnector.addLayer(resoMarker);
resonatorsWithConnector.addLayer(connMarker);
}
resonatorsWithConnector.options = {
details: portalDetails.resonatorArray.resonators,
guid: portal.options.guid
};
this.resonators[portal.options.guid] = resonatorsWithConnector;
this.resonatorLayerGroup.addLayer(resonatorsWithConnector);
// bring portal in front of resonator connector
portal.bringToFront();
}
window.plugin.drawResonators.Render.prototype.createResoMarker = function(resoData, resoLatLng, portalSelected) {
var resoProperty = this.getStyler().getResonatorStyle(resoData, portalSelected);
resoProperty.type = 'resonator';
resoProperty.details = resoData;
var reso = L.circleMarker(resoLatLng, resoProperty);
return reso;
}
window.plugin.drawResonators.Render.prototype.createConnMarker = function(resoData, resoLatLng, portalLatLng, portalSelected) {
var connProperty = this.getStyler().getConnectorStyle(resoData, portalSelected);
connProperty.type = 'connector';
connProperty.details = resoData;
var conn = L.polyline([portalLatLng, resoLatLng], connProperty);
return conn;
}
window.plugin.drawResonators.Render.prototype.getResonatorLatLng = function(dist, slot, portalLatLng) {
// offset in meters
var dn = dist*SLOT_TO_LAT[slot];
var de = dist*SLOT_TO_LNG[slot];
// Coordinate offset in radians
var dLat = dn/EARTH_RADIUS;
var dLon = de/(EARTH_RADIUS*Math.cos(Math.PI/180*portalLatLng[0]));
// OffsetPosition, decimal degrees
var lat0 = portalLatLng[0] + dLat * 180/Math.PI;
var lon0 = portalLatLng[1] + dLon * 180/Math.PI;
return [lat0, lon0];
}
window.plugin.drawResonators.Render.prototype.deleteResonatorEntities = function(portalGuid) {
if (!(portalGuid in this.resonators)) return;
var r = this.resonators[portalGuid];
this.resonatorLayerGroup.removeLayer(r);
delete this.resonators[portalGuid];
}
// Save zoom level before zoom, use to determine redraw of resonator
window.plugin.drawResonators.Render.prototype.handleResonatorEntitiesBeforeZoom = function() {
this.beforeZoomLevel = map.getZoom();
}
window.plugin.drawResonators.Render.prototype.handleResonatorEntitiesAfterZoom = function() {
if(!this.isResonatorsShow()) {
this.clearAllResonators();
return;
}
// Draw all resonators if they were not drawn
if(!this.isResonatorsShowBeforeZoom()) {
this.drawAllResonators();
}
}
window.plugin.drawResonators.Render.prototype.handleEnableZoomLevelChange = function(zoomLevel) {
this.enableZoomLevel = zoomLevel;
if(!this.isResonatorsShow()) {
this.clearAllResonators();
return;
}
// Draw all resonators if they were not drawn
if(!Object.keys(this.resonators).length > 0) {
this.drawAllResonators();
}
}
window.plugin.drawResonators.Render.prototype.clearAllResonators = function() {
this.resonatorLayerGroup.clearLayers();
this.resonators = {};
}
window.plugin.drawResonators.Render.prototype.drawAllResonators = function() {
var render = this;
// loop through level of portals, only draw if the portal is shown on map
for (var guid in window.portals) {
var portal = window.portals[guid];
// FIXME: need to find a proper way to check if a portal is added to the map without depending on leaflet internals
// (and without depending on portalsLayers either - that's IITC internal)
if (portal._map) {
render.createResonatorEntities(portal);
}
}
}
window.plugin.drawResonators.Render.prototype.portalSelectionChange = function(data) {
this.toggleSelectedStyle(data.selectedPortalGuid);
this.toggleSelectedStyle(data.unselectedPortalGuid);
}
window.plugin.drawResonators.Render.prototype.toggleSelectedStyle = function(portalGuid) {
if (!(portalGuid in this.resonators)) return;
var render = this;
var portalSelected = selectedPortal === portalGuid;
var r = this.resonators[portalGuid];
r.eachLayer(function(entity) {
var style;
if(entity.options.type === 'resonator') {
style = render.getStyler().getResonatorStyle(entity.options.details, portalSelected);
} else {
style = render.getStyler().getConnectorStyle(entity.options.details, portalSelected);
}
entity.setStyle(style);
});
}
window.plugin.drawResonators.Render.prototype.addStyler = function(styler) {
this.stylers[styler.name] = styler;
}
window.plugin.drawResonators.Render.prototype.getStylersList = function() {
return Object.keys(this.stylers);
}
window.plugin.drawResonators.Render.prototype.getStyler = function() {
var stylerName = this.useStyler in this.stylers ? this.useStyler : 'Default';
return this.stylers[stylerName];
}
// Change if styler need change, and redraw all resonators using new styler
window.plugin.drawResonators.Render.prototype.changeStyler = function(name) {
if (name === this.useStyler) return;
for(stylerName in this.stylers) {
if(stylerName === name) {
if(this.stylers[this.useStyler]) this.stylers[this.useStyler].onDisableFunc();
this.useStyler = stylerName;
this.stylers[this.useStyler].onEnableFunc();
this.clearAllResonators();
this.drawAllResonators();
return;
}
}
}
window.plugin.drawResonators.Render.prototype.refreshStyler = function() {
this.clearAllResonators();
this.drawAllResonators();
}
window.plugin.drawResonators.Render.prototype.isResonatorsShow = function() {
return map.getZoom() >= this.enableZoomLevel;
}
window.plugin.drawResonators.Render.prototype.isResonatorsShowBeforeZoom = function() {
return this.beforeZoomLevel >= this.enableZoomLevel;
}
//////// Styler for getting resonator and connector style ////////
window.plugin.drawResonators.Styler = function(options) {
options = options || {};
this.name = options['name'] || 'Default';
this.otherOptions = options['otherOptions'];
this.getResonatorStyle = options['resonatorStyleFunc'] || this.defaultResonatorStyle;
this.getConnectorStyle = options['connectorStyleFunc'] || this.defaultConnectorStyle;
this.onEnableFunc = options['onEnableFunc'] || function() {};
this.onDisableFunc = options['onDisableFunc'] || function() {};
}
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_SELECTED = {
color: '#fff',
weight: 1.1,
radius: 4,
opacity: 1,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_NON_SELECTED = {
color: '#aaa',
weight: 1,
radius: 3,
opacity: 1,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_LINE_SELECTED = {
opacity: 0.7,
weight: 3,
color: '#FFA000',
dashArray: '0,10' + (new Array(25).join(',8,4')),
fill: false,
clickable: false};
window.plugin.drawResonators.Styler.prototype.DEFAULT_OPTIONS_RESONATOR_LINE_NON_SELECTED = {
opacity: 0.25,
weight: 2,
color: '#FFA000',
dashArray: '0,10' + (new Array(25).join(',8,4')),
fill: false,
clickable: false};
window.plugin.drawResonators.Styler.prototype.defaultResonatorStyle = function(resoDetail, selected) {
var resoSharedStyle = selected
? this.DEFAULT_OPTIONS_RESONATOR_SELECTED
: this.DEFAULT_OPTIONS_RESONATOR_NON_SELECTED;
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level],
}, resoSharedStyle);
return resoStyle;
}
window.plugin.drawResonators.Styler.prototype.defaultConnectorStyle = function(resoDetail, selected) {
var connStyle = selected
? this.DEFAULT_OPTIONS_RESONATOR_LINE_SELECTED
: this.DEFAULT_OPTIONS_RESONATOR_LINE_NON_SELECTED;
return connStyle;
}
//////// Options for storing and loading options ////////
window.plugin.drawResonators.Options = function() {
this._options = {};
this._callbacks = {};
}
window.plugin.drawResonators.Options.prototype.addCallback = function(name, callback) {
if (!this._callbacks[name]) {
this._callbacks[name] = [];
}
this._callbacks[name].push(callback);
}
window.plugin.drawResonators.Options.prototype.newOption = function(name, defaultValue) {
this._options[name] = this.loadLocal(this.getStorageKey(name), defaultValue)
}
window.plugin.drawResonators.Options.prototype.getOption = function(name) {
return this._options[name];
}
window.plugin.drawResonators.Options.prototype.removeOption = function(name) {
delete this._options[name];
delete this._callbacks[name];
}
window.plugin.drawResonators.Options.prototype.changeOption = function(name, value) {
if(!(name in this._options)) return false;
if(value === this._options[name]) return false;
this._options[name] = value;
this.storeLocal(this.getStorageKey(name), this._options[name]);
if (this._callbacks[name] !== null) {
for(var i in this._callbacks[name]) {
this._callbacks[name][i](value);
}
}
}
window.plugin.drawResonators.Options.prototype.getStorageKey = function(name) {
return 'plugin-drawResonators-option-' + name;
}
window.plugin.drawResonators.Options.prototype.loadLocal = function(key, defaultValue) {
var objectJSON = localStorage[key];
if(objectJSON) {
return JSON.parse(objectJSON);
} else {
return defaultValue;
}
}
window.plugin.drawResonators.Options.prototype.storeLocal = function(key, value) {
if(typeof(value) !== 'undefined' && value !== null) {
localStorage[key] = JSON.stringify(value);
} else {
localStorage.removeItem(key);
}
}
//////// Dialog
window.plugin.drawResonators.Dialog = function() {
this._dialogEntries = {};
}
window.plugin.drawResonators.Dialog.prototype.addLink = function() {
$('#toolbox').append('<a id="draw-reso-show-dialog" onclick="window.plugin.drawResonators.dialog.show();">Resonators</a> ');
}
window.plugin.drawResonators.Dialog.prototype.addEntry = function(name, dialogEntry) {
this._dialogEntries[name] = dialogEntry;
this.change();
}
window.plugin.drawResonators.Dialog.prototype.removeEntry = function(name) {
delete this._dialogEntries[name];
this.change();
}
window.plugin.drawResonators.Dialog.prototype.show = function() {
window.dialog({html: this.getDialogHTML(), title: 'Resonators', modal: true, id: 'draw-reso-setting'});
// Attach entries event
for(var name in this._dialogEntries) {
var events = this._dialogEntries[name].getOnEvents();
for(var i in events) {
var event = events[i];
$('#draw-reso-dialog').on(event.event, '#' + event.id, event.callback);
}
}
}
window.plugin.drawResonators.Dialog.prototype.change = function() {
if($('#draw-reso-dialog').length > 0) this.show();
}
window.plugin.drawResonators.Dialog.prototype.getDialogHTML = function() {
var html = '<div id="draw-reso-dialog">'
for(var name in this._dialogEntries) {
html += '<div>'
+ this._dialogEntries[name].getHTML()
+ '</div>';
}
html += '</div>';
return html;
}
//////// ListDialogEntry
window.plugin.drawResonators.ListDialogEntry = function(options) {
this._name = options['name'];
this._label = options['label'];
this._valueFunc = options['valueFunc'];
this._valuesList = options['valuesList'];
this._valuesListFunc = options['valuesListFunc'];
this._onChangeCallback = options['onChangeCallback'];
}
window.plugin.drawResonators.ListDialogEntry.prototype.getHTML = function() {
var curValue = this._valueFunc();
var valuesList = this._valuesList ? this._valuesList : this._valuesListFunc();
var html = '<label for="' + this.getSelectId() + '">'
+ this._label + ': '
+ '</label>'
+ '<select id="' + this.getSelectId() + '">';
var noLabel = valuesList instanceof Array;
for(var label in valuesList) {
var selected = valuesList[label] === curValue;
html += '<option value="' + valuesList[label] + '" '
+ (selected ? 'selected="selected"' : '')
+'>'
+ (noLabel ? valuesList[label] : label)
+ '</option>';
}
html += '</select>';
return html;
}
window.plugin.drawResonators.ListDialogEntry.prototype.getOnEvents = function() {
return [{'event': 'change',
'id': this.getSelectId(),
'callback': this._onChangeCallback
}];
}
window.plugin.drawResonators.ListDialogEntry.prototype.getSelectId = function() {
return 'draw-reso-option-' + this._name;
}
//////// TextboxDialogEntry
window.plugin.drawResonators.TextboxDialogEntry = function(options) {
this._name = options['name'];
this._label = options['label'];
this._valueFunc = options['valueFunc'];
this._onChangeCallback = options['onChangeCallback'];
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getHTML = function() {
var curValue = this._valueFunc();
var html = '<label for="' + this.getInputId() + '">'
+ this._label + ': '
+ '</label>'
+ '<input type="text" size="20" id="' + this.getInputId() + '" '
+ 'value="' + curValue + '" />';
return html;
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getOnEvents = function() {
return [{'event': 'change',
'id': this.getInputId(),
'callback': this._onChangeCallback
}];
}
window.plugin.drawResonators.TextboxDialogEntry.prototype.getInputId = function() {
return 'draw-reso-option-' + this._name;
}
window.plugin.drawResonators.setupStyler = function() {
var thisPlugin = window.plugin.drawResonators;
var highlightedReso = {color: '#fff', weight: 2, radius: 4, opacity: 1, clickable: false};
var normalReso = {color: '#aaa', weight: 1, radius: 3, opacity: 1, clickable: false};
var selectedReso = {color: '#eee', weight: 1.1, radius: 4, opacity: 1, clickable: false};
var highlightedConn = {opacity: 0.7, weight: 3, color: '#FFA000', dashArray: '0,10,999', color: '#FFA000', fill: false, clickable: false};
var normalConn = {opacity: 0.25, weight: 2, color: '#FFA000', dashArray: '0,10' + (new Array(25).join(',8,4')), fill: false, clickable: false};
var selectedConn = {opacity: 0.7, weight: 3, color: '#FFA000', dashArray: '0,10' + (new Array(25).join(',8,4')), fill: false, clickable: false};
// Styler for highlighting resonators deployed by me
var myReso = {
name: 'Highlight my resonators',
otherOptions: {
'highlightedReso' : highlightedReso,
'normalReso' : normalReso,
'selectedReso' : selectedReso,
'highlightedConn' : highlightedConn,
'normalConn' : normalConn,
'selectedConn' : selectedConn
},
resonatorStyleFunc: function(resoDetail, selected) {
var mine = resoDetail.ownerGuid === PLAYER.guid;
var resoSharedStyle = mine
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (mine ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var mine = resoDetail.ownerGuid === PLAYER.guid;
var connStyle = mine
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(myReso));
// Styler for highlighting L8 resonators
var l8Reso = {
name: 'Highlight L8 resonators',
otherOptions: {
'highlightedReso' : highlightedReso,
'normalReso' : normalReso,
'selectedReso' : selectedReso,
'highlightedConn' : highlightedConn,
'normalConn' : normalConn,
'selectedConn' : selectedConn
},
resonatorStyleFunc: function(resoDetail, selected) {
var l8 = resoDetail.level === 8;
var resoSharedStyle = l8
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (l8 ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var l8 = resoDetail.level === 8;
var connStyle = l8
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(l8Reso));
// Styler for highlighting resonators with less than X% energy
var lessThanXPctReso = {
name: 'Highlight < X% resonators',
otherOptions: {
'highlightedReso': highlightedReso,
'normalReso': normalReso,
'selectedReso': selectedReso,
'highlightedConn': highlightedConn,
'normalConn': normalConn,
'selectedConn': selectedConn,
'pct': 15,
'dialogEntry': new thisPlugin.TextboxDialogEntry({
name: 'resoLessThanPct-pct',
label: 'Percentage',
valueFunc: function() {return thisPlugin.options.getOption('styler-resoLessThanPct-pct')},
onChangeCallback: function(event) {thisPlugin.options.changeOption('styler-resoLessThanPct-pct', parseInt(event.target.value));}
})
},
resonatorStyleFunc: function(resoDetail, selected) {
var highlight = (resoDetail.energyTotal * 100) < (RESO_NRG[resoDetail.level] * this.otherOptions.pct);
var resoSharedStyle = highlight
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level]
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var highlight = (resoDetail.energyTotal * 100) < (RESO_NRG[resoDetail.level] * this.otherOptions.pct);
var connStyle = highlight
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
},
onEnableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
var thisStyler = this;
// Add option
thisPlugin.options.newOption('styler-resoLessThanPct-pct', 15);
thisPlugin.options.addCallback('styler-resoLessThanPct-pct', function(value) {
thisStyler.otherOptions.pct = value;
thisPlugin.render.refreshStyler();
});
thisStyler.otherOptions.pct = thisPlugin.options.getOption('styler-resoLessThanPct-pct');
// Add dialog entry
thisPlugin.dialog.addEntry('resoLessThanPct-pct', this.otherOptions.dialogEntry);
},
onDisableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
// Remove option
thisPlugin.options.removeOption('styler-resoLessThanPct-pct');
// Remove dialog entry
thisPlugin.dialog.removeEntry('resoLessThanPct-pct');
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(lessThanXPctReso));
// Styler for highlighting resonators deployed by specific player
var resoOfSpecificPlayer = {
name: 'Highlight resonators by player',
otherOptions: {
'highlightedReso': highlightedReso,
'normalReso': normalReso,
'selectedReso': selectedReso,
'highlightedConn': highlightedConn,
'normalConn': normalConn,
'selectedConn': selectedConn,
'player': '',
'playerGuid': '',
'dialogEntry': new thisPlugin.TextboxDialogEntry({
name: 'resoOfSpecificPlayer-player',
label: 'Player name',
valueFunc: function() {return thisPlugin.options.getOption('styler-resoOfSpecificPlayer-player')},
onChangeCallback: function(event) {thisPlugin.options.changeOption('styler-resoOfSpecificPlayer-player', event.target.value);}
})
},
resonatorStyleFunc: function(resoDetail, selected) {
var highlight = resoDetail.ownerGuid === this.otherOptions.playerGuid;
var resoSharedStyle = highlight
? this.otherOptions.highlightedReso
: (selected ? this.otherOptions.selectedReso : this.otherOptions.normalReso);
var resoStyle = $.extend({
fillColor: COLORS_LVL[resoDetail.level],
fillOpacity: resoDetail.energyTotal/RESO_NRG[resoDetail.level] * (highlight ? 1 : 0.75)
}, resoSharedStyle);
return resoStyle;
},
connectorStyleFunc: function(resoDetail, selected) {
var highlight = resoDetail.ownerGuid === this.otherOptions.playerGuid;
var connStyle = highlight
? this.otherOptions.highlightedConn
: (selected ? this.otherOptions.selectedConn : this.otherOptions.normalConn);
return connStyle;
},
onEnableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
var thisStyler = this;
// Add option
thisPlugin.options.newOption('styler-resoOfSpecificPlayer-player', '');
thisPlugin.options.addCallback('styler-resoOfSpecificPlayer-player', function(value) {
thisStyler.otherOptions.player = value;
thisStyler.otherOptions.playerGuid = window.playerNameToGuid(value);
thisPlugin.render.refreshStyler();
});
thisStyler.otherOptions.player = thisPlugin.options.getOption('styler-resoOfSpecificPlayer-player');
thisStyler.otherOptions.playerGuid = window.playerNameToGuid(thisStyler.otherOptions.player);
// Add dialog entry
thisPlugin.dialog.addEntry('resoOfSpecificPlayer-player', this.otherOptions.dialogEntry);
},
onDisableFunc: function() {
var thisPlugin = window.plugin.drawResonators;
// Remove option
thisPlugin.options.removeOption('styler-resoOfSpecificPlayer-player');
// Remove dialog entry
thisPlugin.dialog.removeEntry('resoOfSpecificPlayer-player');
}
};
thisPlugin.render.addStyler(new thisPlugin.Styler(resoOfSpecificPlayer));
thisPlugin.render.changeStyler(thisPlugin.options.getOption('useStyler'));
}
window.plugin.drawResonators.setupOptions = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize options
thisPlugin.options = new thisPlugin.Options();
thisPlugin.options.newOption('enableZoomLevel', 17);
thisPlugin.options.newOption('useStyler', 'Default');
}
window.plugin.drawResonators.setupDialog = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize dialog
thisPlugin.dialog = new thisPlugin.Dialog();
var enableZoomLevelDialogEntryOptions = {
name: 'enable-zoom-level',
label: 'Enable zoom level',
valueFunc: function() {return thisPlugin.options.getOption('enableZoomLevel')},
valuesList: {'15':15, '16':16, '17':17, '18':18, '19':19, '20':20, 'None':99},
onChangeCallback: function(event) {thisPlugin.options.changeOption('enableZoomLevel', parseInt(event.target.value));}
};
var enableZoomLevelDialogEntry = new thisPlugin.ListDialogEntry(enableZoomLevelDialogEntryOptions);
thisPlugin.dialog.addEntry('enable-zoom-level', enableZoomLevelDialogEntry);
var stylerDialogEntryOptions = {
name: 'use-styler',
label: 'Styler',
valueFunc: function() {return thisPlugin.options.getOption('useStyler')},
valuesListFunc: thisPlugin.render.getStylersList,
onChangeCallback: function(event) {thisPlugin.options.changeOption('useStyler', event.target.value);}
};
var stylerDialogEntry = new thisPlugin.ListDialogEntry(stylerDialogEntryOptions);
thisPlugin.dialog.addEntry('use-styler', stylerDialogEntry);
thisPlugin.dialog.addLink();
}
var setup = function() {
var thisPlugin = window.plugin.drawResonators;
// Initialize options
thisPlugin.setupOptions();
// Initialize render
var renderOptions = {'enableZoomLevel': thisPlugin.options.getOption('enableZoomLevel')};
thisPlugin.render = new thisPlugin.Render(renderOptions);
// callback run at option change
thisPlugin.options.addCallback('enableZoomLevel', thisPlugin.render.handleEnableZoomLevelChange);
thisPlugin.options.addCallback('useStyler', thisPlugin.render.changeStyler);
// Initialize Dialog
thisPlugin.setupDialog();
// Initialize styler
thisPlugin.setupStyler();
thisPlugin.render.registerHook();
window.addLayerGroup('Resonators', thisPlugin.render.resonatorLayerGroup, true);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,9 +1,9 @@
// ==UserScript==
// @id iitc-plugin-favorite-portals@soulBit
// @name IITC plugin: Favorite Portals
// @category Obsolete
// @category Deleted
// @version 0.2.0.@@DATETIMEVERSION@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] DEPRECATED. Please use "Bookmarks for maps and portals" instead.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -13,161 +13,3 @@
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
window.plugin.favoritePortals = function() {};
window.plugin.favoritePortals.portalList = {};
window.plugin.favoritePortals.LOCAL_STORAGE_KEY = "plugin-favorite-portals";
window.plugin.favoritePortals.hasLocalStorage = ('localStorage' in window && window['localStorage'] !== null);
window.plugin.favoritePortals.onDetailsUpdated = function(data) {
$('.linkdetails').prepend("<div title='Favorite this portal' class='toggle-favorite-portal' onclick='window.plugin.favoritePortals.togglePortal()' />");
if(window.plugin.favoritePortals.portalList[window.selectedPortal]) {
$('.toggle-favorite-portal').addClass( 'portal-on' );
window.plugin.favoritePortals.portalList[window.selectedPortal] = window.portals[window.selectedPortal].options;
window.plugin.favoritePortals.savePortals();
}
}
window.plugin.favoritePortals.display = function() {
var output = '';
if (!window.plugin.favoritePortals.hasLocalStorage) {
output += "Favorite portals cannot save any data, please try another browser that supports 'localStorage'.";
} else {
if ($.isEmptyObject(window.plugin.favoritePortals.portalList)) {
output += "No portals have been marked as favorite, click the blue square in the bottom left corner of the portal details to save one.";
} else {
output += "<div class='header'>Portal list (values not current till portal on screen):</div>";
output += "<div class='portal-list-container'>";
var portals = [], dataChanged = false, portalData;
$.each( window.plugin.favoritePortals.portalList, function(i, portal) {
if(window.portals[i]) {
dataChanged = true;
window.plugin.favoritePortals.portalList[ i ] = window.portals[i].options;
}
portalData = (window.portals[i]) ? window.portals[i].options : portal;
portals.push({'guid': i, 'portalData': portalData});
});
if(dataChanged)
window.plugin.favoritePortals.savePortals();
portals.sort(function(a,b) {
var nameA = a.portalData.details.portalV2.descriptiveText.TITLE.toLowerCase();
var nameB = b.portalData.details.portalV2.descriptiveText.TITLE.toLowerCase();
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0;
});
output += "<ol>";
var teamName, energy;
$.each(portals, function(i, portal) {
portalData = portal.portalData;
output += "<li name='" + portal.guid + "'>";
output += "<a class='delete-favorite-portal' title='Delete favorite?' onclick='window.plugin.favoritePortals.onDelete(" + '"' + portal.guid + '"' + ");return false'>X</a>";
output += "<a onclick='window.plugin.favoritePortals.onPortalClicked(" + ' "' + portal.guid + '", [' + (portalData.details.locationE6.latE6 / 1000000) + "," + (portal.portalData.details.locationE6.lngE6 / 1000000) + "]);return false'>" + portalData.details.portalV2.descriptiveText.TITLE + "</a>";
teamName = portalData.details.controllingTeam.team;
output += " - L" + Math.floor( portalData.level );
energy = Math.floor( window.getCurrentPortalEnergy(portalData.details) / window.getPortalEnergy(portalData.details) * 100 );
if(!isNaN(energy))
output += " @" + energy + "%";
output += ": " + ( (teamName === "ALIENS") ? "Enlightened" : teamName[0] + teamName.slice(1).toLowerCase() );
if(portalData.details.portalV2.linkedEdges.length > 0 || portalData.details.portalV2.linkedFields.length > 0)
output += ", " + portalData.details.portalV2.linkedEdges.length + " links & " + portalData.details.portalV2.linkedFields.length + " fields";
output += "</li>";
});
output += "</ol>"
output += "</div>";
}
}
window.dialog({'html': "<div id='favorite-portal-list'>" + output + "</div>", 'title': 'Favorite portals', 'id': 'favorite-portals'});
}
window.plugin.favoritePortals.onDelete = function(guid) {
delete window.plugin.favoritePortals.portalList[ guid ];
if(window.selectedPortal && window.selectedPortal === guid)
$('.toggle-favorite-portal').removeClass( 'portal-on' ).addClass( 'portal-off' );
$("li[name='" + guid + "']").remove();
window.plugin.favoritePortals.savePortals();
}
window.plugin.favoritePortals.onPortalClicked = function(guid, coords) {
window.zoomToAndShowPortal(guid, coords);
$('#dialog-favorite-portals').dialog('close');
}
window.plugin.favoritePortals.togglePortal = function() {
if(window.plugin.favoritePortals.portalList[window.selectedPortal]) {
$('.toggle-favorite-portal').removeClass('portal-on').addClass('portal-off');
delete window.plugin.favoritePortals.portalList[ window.selectedPortal ];
} else {
$('.toggle-favorite-portal').removeClass('portal-off').addClass('portal-on');
window.plugin.favoritePortals.portalList[window.selectedPortal] = window.portals[window.selectedPortal].options;
}
window.plugin.favoritePortals.savePortals();
}
window.plugin.favoritePortals.savePortals = function() {
var portalsObject = {'portals': window.plugin.favoritePortals.portalList};
var portalListJSON = JSON.stringify(portalsObject);
localStorage[window.plugin.favoritePortals.LOCAL_STORAGE_KEY] = portalListJSON;
}
window.plugin.favoritePortals.loadPortals = function() {
var portalListJSON = localStorage[window.plugin.favoritePortals.LOCAL_STORAGE_KEY];
if(!portalListJSON) return;
var portalsObject = JSON.parse(portalListJSON);
window.plugin.favoritePortals.portalList = portalsObject.portals;
}
window.plugin.favoritePortals.setup = function() {
window.plugin.favoritePortals.loadPortals();
window.addHook('portalDetailsUpdated', window.plugin.favoritePortals.onDetailsUpdated);
$('#toolbox').append("<a onclick='window.plugin.favoritePortals.display()' title='Create a list of favorite portals'>Favorite Portals</a>");
$("<style>").prop("type", "text/css").html(".toggle-favorite-portal {\
width: 13px;\
height: 13px;\
margin-left: 10px;\
vertical-align: middle;\
display: inline-block;\
cursor: pointer;\
border: 1px solid #20A8B1;\
}\
.portal-on {\
background-color: #20A8B1;\
}\
.portal-off {\
}\
.linkdetails {\
margin-bottom: 5px;\
}\
.delete-favorite-portal {\
width: 10px;\
height: 10px;\
color: #FFCC00;\
border: 2px solid #20A8B1;\
margin-right: 10px;\
padding-left: 3px;\
padding-right: 3px;\
font-weight: bolder;\
}\
#favorite-portal-list {\
padding: 5px;\
}\
#favorite-portal-list li {\
line-height: 1.8;\
}").appendTo("head");
};
var setup = window.plugin.favoritePortals.setup;
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-guess-player-levels@breunigs
// @name IITC plugin: guess player level
// @category Info
// @version 0.4.9.@@DATETIMEVERSION@@
// @version 0.5.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -21,35 +21,81 @@
// use own namespace for plugin
window.plugin.guessPlayerLevels = function() {};
// we prepend a hash sign (#) in front of the player name in storage in order to prevent accessing a pre-defined property
// (like constructor, __defineGetter__, etc.
window.plugin.guessPlayerLevels.setupCallback = function() {
$('#toolbox').append(' <a onclick="window.plugin.guessPlayerLevels.guess()" title="Show player level guesses based on resonator placement in displayed portals">Guess player levels</a>');
addHook('portalAdded', window.plugin.guessPlayerLevels.extractPortalData);
addHook('portalDetailLoaded', window.plugin.guessPlayerLevels.extractPortalData);
addHook('publicChatDataAvailable', window.plugin.guessPlayerLevels.extractChatData);
}
// This function is intended to be called by other plugins
window.plugin.guessPlayerLevels.fetchLevelByPlayer = function(guid) {
return(window.localStorage['level-' + guid]);
window.plugin.guessPlayerLevels.fetchLevelByPlayer = function(nick) {
var cache = window.plugin.guessPlayerLevels._nameToLevelCache;
if(cache['#' + nick] === undefined)
cache = window.plugin.guessPlayerLevels._loadLevels();
var details = cache['#' + nick];
if(details === undefined)
return 1;
if(typeof details === 'number')
return details;
return details.guessed;
}
window.plugin.guessPlayerLevels._nameToGuidCache = {};
// This function is intended to be called by other plugins
window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer = function(nick) {
var cache = window.plugin.guessPlayerLevels._nameToLevelCache;
if(cache['#' + nick] === undefined)
cache = window.plugin.guessPlayerLevels._loadLevels();
var details = cache['#' + nick];
if(details === undefined)
return {min: 1, guessed: 1};
if(typeof details === 'number')
return {min: 1, guessed: details};
return details;
}
window.plugin.guessPlayerLevels._nameToLevelCache = {};
window.plugin.guessPlayerLevels._localStorageLastUpdate = 0;
window.plugin.guessPlayerLevels._loadLevels = function() {
// no use in reading localStorage repeatedly
if(window.plugin.guessPlayerLevels._localStorageLastUpdate < Date.now() - 10*1000) {
try {
var cache = JSON.parse(localStorage['plugin-guess-player-levels'])
window.plugin.guessPlayerLevels._nameToLevelCache = cache;
window.plugin.guessPlayerLevels._localStorageLastUpdate = Date.now();
} catch(e) {
}
}
return window.plugin.guessPlayerLevels._nameToLevelCache;
}
window.plugin.guessPlayerLevels.setLevelTitle = function(dom) {
// expects dom node with nick in its child text node
var el = $(dom);
var nick = el.text();
var guid = window.playerNameToGuid(nick);
var level = guid ? localStorage['level-'+guid] : null;
var details = window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer(nick);
var text;
if (level) {
text = 'Min player level: ' + level + ' (guessed)';
} else {
text = 'Min player level unknown';
if(details.min == 8)
text = 'Player level: 8';
else {
text = 'Min player level: ' + details.min;
if(details.min != details.guessed)
text += '\nGuessed player level: ' + details.guessed;
}
window.setupTooltips(el);
/*
This code looks hacky but since we are a little late within the mouseenter so
we need to improvise a little. The open method doesn't open the tooltip directly.
@ -63,13 +109,15 @@ window.plugin.guessPlayerLevels.setLevelTitle = function(dom) {
}
window.plugin.guessPlayerLevels.setupChatNickHelper = function() {
$(document).on('mouseenter', '.nickname', function() {
$(document).on('mouseenter', '.nickname, .pl_nudge_player', function() {
window.plugin.guessPlayerLevels.setLevelTitle(this);
});
}
window.plugin.guessPlayerLevels.extractPortalData = function(data) {
var r = data.portal.options.details.resonatorArray.resonators;
if(!data.success) return;
var r = data.details.resonatorArray.resonators;
//due to the Jarvis Virus/ADA Refactor it's possible for a player to own resonators on a portal
//at a higher level than the player themselves. It is not possible to detect for sure when this
@ -96,29 +144,98 @@ window.plugin.guessPlayerLevels.extractPortalData = function(data) {
$.each(perPlayerResMaxLevel, function(guid, level) {
if (perPlayerResMaxLevelCount[guid] <= window.MAX_RESO_PER_PLAYER[level]) {
var p = 'level-'+guid;
if(!window.localStorage[p] || window.localStorage[p] < level)
window.localStorage[p] = level;
window.plugin.guessPlayerLevels.savePlayerLevel(guid, level);
}
});
}
window.plugin.guessPlayerLevels.extractChatData = function(data) {
data.raw.result.forEach(function(msg) {
var plext = msg[2].plext;
if(plext.plextType == 'SYSTEM_BROADCAST'
&& plext.markup.length==5
&& plext.markup[0][0] == 'PLAYER'
&& plext.markup[1][0] == 'TEXT'
&& plext.markup[1][1].plain == ' deployed an '
&& plext.markup[2][0] == 'TEXT'
&& plext.markup[2][0] == 'TEXT'
&& plext.markup[3][0] == 'TEXT'
&& plext.markup[3][1].plain == ' Resonator on ') {
var nick = plext.markup[0][1].plain;
var lvl = parseInt(plext.markup[2][1].plain.substr(1));
window.plugin.guessPlayerLevels.savePlayerLevel(nick, lvl, true);
}
});
};
window.plugin.guessPlayerLevels.savePlayerLevel = function(nick, level, safe) {
var cache = window.plugin.guessPlayerLevels._loadLevels();
var details = cache['#' + nick];
if(details === undefined)
details = {min: 1, guessed: 1};
if(typeof details === 'number')
details = {min: 1, guessed: details};
if(safe) {
if(details.min >= level)
return;
details.min = level;
if(details.guessed < details.min)
details.guessed = details.min;
} else {
if(details.guessed >= level)
return;
details.guessed = level;
}
window.plugin.guessPlayerLevels._nameToLevelCache['#' + nick] = details;
// to minimize accesses to localStorage, writing is delayed a bit
if(window.plugin.guessPlayerLevels._writeTimeout)
clearTimeout(window.plugin.guessPlayerLevels._writeTimeout);
window.plugin.guessPlayerLevels._writeTimeout = setTimeout(function() {
localStorage['plugin-guess-player-levels'] = JSON.stringify(window.plugin.guessPlayerLevels._nameToLevelCache);
}, 500);
}
window.plugin.guessPlayerLevels.guess = function() {
var playersRes = {};
var playersEnl = {};
$.each(window.portals, function(ind, portal) {
var r = portal.options.details.resonatorArray.resonators;
$.each(r, function(ind, reso) {
if(!reso) return true;
if(isSystemPlayer(reso.ownerGuid)) return true;
$.each(window.portals, function(guid,p) {
var details = portalDetail.get(guid);
if(details) {
var r = details.resonatorArray.resonators;
$.each(r, function(ind, reso) {
if(!reso) return true;
var nick = reso.ownerGuid;
if(isSystemPlayer(nick)) return true;
var lvl = localStorage['level-' + reso.ownerGuid];
var nick = getPlayerName(reso.ownerGuid);
if(portal.options.team === TEAM_ENL)
playersEnl[nick] = lvl;
else
playersRes[nick] = lvl;
});
var lvl = window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer(nick).min;
if(!lvl) return true;
if(getTeam(details) === TEAM_ENL)
playersEnl[nick] = lvl;
else
playersRes[nick] = lvl;
});
if(details.captured) {
var nick = details.captured.capturingPlayerId
if(isSystemPlayer(nick)) return true;
var lvl = window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer(nick).min;
if(!lvl) return true;
if(getTeam(details) === TEAM_ENL)
playersEnl[nick] = lvl;
else
playersRes[nick] = lvl;
}
}
});
var s = 'Players have at least the following level:\n\n';
@ -129,18 +246,30 @@ window.plugin.guessPlayerLevels.guess = function() {
var totallvlR = 0;
var totallvlE = 0;
var max = Math.max(namesR.length, namesE.length);
for(var i = 0; i < max; i++) {
var nickR = namesR[i];
var lvlR = playersRes[nickR];
var lineR = nickR ? nickR + ':\t' + lvlR : '\t';
if(!isNaN(parseInt(lvlR)))
totallvlR += parseInt(lvlR);
var nickE = namesE[i];
var lvlE = playersEnl[nickE];
var lineE = nickE ? nickE + ':\t' + lvlE : '\t';
if(!isNaN(parseInt(lvlE)))
totallvlE += parseInt(lvlE);
function makeRow(nick, lvl, team) {
if(!nick)
return '\t';
var color = COLORS[team];
if (nick === window.PLAYER.nickname) color = '#fd6'; //highlight the player's name in a unique colour (similar to @player mentions from others in the chat text itself)
return '<mark class="nickname" style="color:'+color+'">'+nick+'</mark>\t' + lvl;
}
var nick, lvl, lineE, lineR;
for(var i = 0; i < max; i++) {
nick = namesR[i];
lvl = playersRes[nick];
lineR = makeRow(nick, lvl, TEAM_RES);
if(!isNaN(parseInt(lvl)))
totallvlR += parseInt(lvl);
nick = namesE[i];
lvl = playersEnl[nick];
lineE = makeRow(nick, lvl, TEAM_ENL);
if(!isNaN(parseInt(lvl)))
totallvlE += parseInt(lvl);
s += '\n'+lineR + '\t' + lineE + '\n';
}
@ -150,8 +279,8 @@ window.plugin.guessPlayerLevels.guess = function() {
if (namesR.length > 0) averageR = (totallvlR/namesR.length);
if (namesE.length > 0) averageE = (totallvlE/namesE.length);
s += '\nAverage level:\t'+averageR.toFixed(2)+'\tAverage level:\t'+averageE.toFixed(2);
s += '\n\nIf there are some unresolved names, simply try again.'
//console.log(s);
s += '\n\nOnly players from recently viewed portal details are listed.'
dialog({
text: s,
title: 'Player levels: R' + averageR.toFixed(2) + ', E' + averageE.toFixed(2),
@ -160,24 +289,19 @@ window.plugin.guessPlayerLevels.guess = function() {
buttons: {
'RESET GUESSES': function() {
// clear all guessed levels from local storage
$.each(Object.keys(localStorage), function(ind,key) {
if(key.lastIndexOf("level-",0)===0) {
localStorage.removeItem(key);
}
});
localStorage.removeItem('plugin-guess-player-levels')
window.plugin.guessPlayerLevels._nameToLevelCache = {}
// now force all portals through the callback manually
$.each(window.portals, function(guid,p) {
window.plugin.guessPlayerLevels.extractPortalData({portal: p});
var details = portalDetail.get(guid);
if(details)
window.plugin.guessPlayerLevels.extractPortalData({details:details, success:true});
});
// and re-open the dialog (on a minimal timeout - so it's not closed while processing this callback)
setTimeout(window.plugin.guessPlayerLevels.guess,1);
},
},
}
});
//run the name resolving process
resolvePlayerNames();
}
window.plugin.guessPlayerLevels.sort = function(playerHash) {
@ -193,6 +317,14 @@ window.plugin.guessPlayerLevels.sort = function(playerHash) {
var setup = function() {
// we used to sture level guesses as one localStorage key per player, named 'level-PLAYER_GUID'
// they're now stored in a single storage key - 'plugin-guess-player-levels' - so clear these old entries
$.each(Object.keys(localStorage), function(ind,key) {// legacy code - should be removed in the future
if(key.lastIndexOf('level-',0)===0) {
localStorage.removeItem(key);
}
});
window.plugin.guessPlayerLevels.setupCallback();
window.plugin.guessPlayerLevels.setupChatNickHelper();
}

View File

@ -1,111 +1,15 @@
// ==UserScript==
// @id iitc-plugin-ipas-link@graphracer
// @name IITC Plugin: simulate an attack on portal
// @category Portal Info
// @category Deleted
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/xosofox/IPAS
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Adds a link to the portal details to open the portal in IPAS - Ingress Portal Attack Simulator on http://ipas.graphracer.com
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.ipasLink = function() {};
window.plugin.ipasLink.setupCallback = function() {
addHook('portalDetailsUpdated', window.plugin.ipasLink.addLink);
}
window.plugin.ipasLink.addLink = function(d) {
$('.linkdetails').append('<aside><a href="http://ipas.graphracer.com/index.html#' + window.plugin.ipasLink.getHash(d.portalDetails) + '" target="ipaswindow" title="Use IPAS to simulate an attack on this portal">Simulate attack</a></aside>');
}
window.plugin.ipasLink.getHash = function (d) {
var hashParts = [];
$.each(d.resonatorArray.resonators, function (ind, reso) {
if (reso) {
hashParts.push(reso.level + "," + reso.distanceToPortal + "," + reso.energyTotal);
} else {
hashParts.push("1,20,0");
}
});
var resos = hashParts.join(";");
hashParts = [];
$.each(d.portalV2.linkedModArray, function (ind, mod) {
// s - shields
// h - heat sink
// i - intentionally left in
// t - turret
//
// f - force amp
// m - multi-hack
// l - link-amp
//
var modCodes = {
"RES_SHIELD": "s",
"HEATSINK": "h",
"TURRET": "t",
"FORCE_AMP": "f",
"MULTIHACK": "m",
"LINK_AMPLIFIER": "l"
}
var mc = "0";
if (mod) {
if (mod.type in modCodes) {
mc = modCodes[mod.type] + mod.rarity.charAt(0).toLowerCase();
//special for shields to distinguish old/new mitigation
if (mod.type == "RES_SHIELD") {
mc += mod.stats.MITIGATION;
}
}
}
hashParts.push(mc);
});
var shields = hashParts.join(",");
var linkParts = [];
var edges = d.portalV2.linkedEdges;
var portalL = new L.LatLng(d.locationE6.latE6 / 1E6, d.locationE6.lngE6 / 1E6)
$.each(edges, function (ind, edge) {
//calc distance in m here
var distance = 1; //default to 1m, so a low level portal would support it
//Try to find other portals details
var guid = edge.otherPortalGuid
if (window.portals[guid] !== undefined) {
//get other portals details as o
var o = window.portals[guid].options.details;
var otherPortalL = new L.LatLng(o.locationE6.latE6 / 1E6, o.locationE6.lngE6 / 1E6);
var distance = Math.round(portalL.distanceTo(otherPortalL));
}
if (!(edge.isOrigin)) {
distance = distance * -1;
}
linkParts.push(distance);
});
var links = linkParts.join(",");
return resos + "/" + shields + "/" + links; //changed with IPAS 1.1 to / instead of |
}
var setup = function () {
window.plugin.ipasLink.setupCallback();
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-farms@949
// @name IITC plugin: Show farms by level
// @category Info
// @version 1.4.0.@@DATETIMEVERSION@@
// @version 1.4.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -62,7 +62,7 @@ window.plugin.farmFind.getNearbyPortalCount = function(portal){
$.each(window.portals, function(i, otherPortal) {
var thisPortal = new google.maps.LatLng(otherPortal.getLatLng().lat, otherPortal.getLatLng().lng);
if (circle.getBounds().contains(thisPortal))
if (getPortalLevel(otherPortal.options.details) >= window.plugin.farmFind.minLevel) nearby8Portals++;
if (otherPortal.options.level >= window.plugin.farmFind.minLevel) nearby8Portals++;
});
//console.log(nearby8Portals);
return nearby8Portals;

View File

@ -2,7 +2,7 @@
// @id max-links@boombuler
// @name IITC plugin: Max Links
// @category Layer
// @version 0.4.1.@@DATETIMEVERSION@@
// @version 0.4.2.@@DATETIMEVERSION@@
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Calculates how to link the portals to create a reasonably tidy set of links/fields. Enable from the layer chooser. (Max Links is a poor name, but remains for historical reasons.)
@ -22,27 +22,21 @@ window.plugin.maxLinks = function() {};
// const values
window.plugin.maxLinks.MAX_PORTALS_TO_LINK = 200;
// zoom level used for projecting points between latLng and pixel coordinates. may affect precision of triangulation
window.plugin.maxLinks.PROJECT_ZOOM = 16;
window.plugin.maxLinks.STROKE_STYLE = {
color: '#FF0000',
opacity: 1,
weight: 2,
weight: 1.5,
clickable: false,
dashArray: [8,6],
dashArray: [6,4],
smoothFactor: 10,
};
window.plugin.maxLinks.layer = null;
window.plugin.maxLinks.errorMarker = null;
window.plugin.maxLinks.Point = function(x,y) {
this.x=x;
this.y=y;
}
window.plugin.maxLinks.Point.prototype.toString = function() {
return this.x+","+this.y;
}
window.plugin.maxLinks.addErrorMarker = function() {
if (window.plugin.maxLinks.errorMarker == null) {
@ -81,10 +75,13 @@ window.plugin.maxLinks.updateLayer = function() {
var locations = [];
var bounds = map.getBounds();
$.each(window.portals, function(guid, portal) {
var loc = portal.options.details.locationE6;
var nloc = new window.plugin.maxLinks.Point(loc.latE6/1E6, loc.lngE6/1E6);
locations.push(nloc);
var ll = portal.getLatLng();
if (bounds.contains(ll)) {
var p = map.project (portal.getLatLng(), window.plugin.maxLinks.PROJECT_ZOOM);
locations.push(p);
}
});
var triangles = window.delaunay.triangulate(locations);
@ -117,7 +114,11 @@ window.plugin.maxLinks.updateLayer = function() {
//using drawnLinks[a] as a set - so the stored value is of no importance
drawnLinks[a][b] = null;
var poly = L.polyline([[a.x,a.y],[b.x,b.y]], window.plugin.maxLinks.STROKE_STYLE);
// convert back from x/y coordinates to lat/lng for drawing
var alatlng = map.unproject (a, window.plugin.maxLinks.PROJECT_ZOOM);
var blatlng = map.unproject (b, window.plugin.maxLinks.PROJECT_ZOOM);
var poly = L.polyline([alatlng, blatlng], window.plugin.maxLinks.STROKE_STYLE);
poly.addTo(window.plugin.maxLinks.layer);
drawnLinkCount++;
}

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-player-tracker@breunigs
// @name IITC Plugin: Player tracker
// @category Layer
// @version 0.10.0.@@DATETIMEVERSION@@
// @version 0.10.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -165,7 +165,7 @@ window.plugin.playerTracker.processNewData = function(data) {
}
break;
case 'PLAYER':
pguid = markup[1].guid;
pguid = markup[1].plain;
break;
case 'PORTAL':
// link messages are “player linked X to Y” and the player is at
@ -196,7 +196,7 @@ window.plugin.playerTracker.processNewData = function(data) {
if(!playerData || playerData.events.length === 0) {
plugin.playerTracker.stored[pguid] = {
// this always resolves, as the chat delivers this data
nick: window.getPlayerName(pguid),
nick: pguid,
team: json[2].plext.team,
events: [newEvent]
};
@ -250,9 +250,9 @@ window.plugin.playerTracker.getLatLngFromEvent = function(ev) {
//TODO? add weight to certain events, or otherwise prefer them, to give better locations?
var lats = 0;
var lngs = 0;
$.each(ev.latlngs, function() {
lats += this[0];
lngs += this[1];
$.each(ev.latlngs, function(i, latlng) {
lats += latlng[0];
lngs += latlng[1];
});
return L.latLng(lats / ev.latlngs.length, lngs / ev.latlngs.length);
@ -311,16 +311,22 @@ window.plugin.playerTracker.drawData = function() {
var popup = '<span class="nickname '+cssClass+'" style="font-weight:bold;">' + playerData.nick + '</span>';
if(window.plugin.guessPlayerLevels !== undefined &&
window.plugin.guessPlayerLevels.fetchLevelByPlayer !== undefined) {
var playerLevel = window.plugin.guessPlayerLevels.fetchLevelByPlayer(pguid);
if(playerLevel !== undefined) {
popup += '<span style="font-weight:bold;margin-left:10px;">Level '
+ playerLevel
+ ' (guessed)'
+ '</span>';
} else {
popup += '<span style="font-weight:bold;margin-left:10px;">Level unknown</span>'
window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer !== undefined) {
function getLevel(lvl) {
return '<span style="padding:4px;color:white;background-color:'+COLORS_LVL[lvl]+'">'+lvl+'</span>';
}
popup += '<span style="font-weight:bold;margin-left:10px;">';
var playerLevelDetails = window.plugin.guessPlayerLevels.fetchLevelDetailsByPlayer(pguid);
if(playerLevelDetails.min == 8) {
popup += 'Level ' + getLevel(8);
} else {
popup += 'Min level: ' + getLevel(playerLevelDetails.min);
if(playerLevelDetails.min != playerLevelDetails.guessed)
popup += ', guessed level: ' + getLevel(playerLevelDetails.guessed);
}
popup += '</span>';
}
popup += '<br>'
@ -344,15 +350,15 @@ window.plugin.playerTracker.drawData = function() {
var eventPortal = []
var closestPortal;
var mostPortals = 0;
$.each(last.guids, function() {
if(eventPortal[this]) {
eventPortal[this]++;
$.each(last.guids, function(i, guid) {
if(eventPortal[guid]) {
eventPortal[guid]++;
} else {
eventPortal[this] = 1;
eventPortal[guid] = 1;
}
if(eventPortal[this] > mostPortals) {
mostPortals = eventPortal[this];
closestPortal = this;
if(eventPortal[guid] > mostPortals) {
mostPortals = eventPortal[guid];
closestPortal = guid;
}
});

View File

@ -1,107 +1,15 @@
// ==UserScript==
// @id iitc-plugin-players-resonators@rbino
// @name IITC plugin: Player's Resonators
// @category Deleted
// @version 0.1.5.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] The plugins finds the resonators of a given player. The input is in the sidebar.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
/*********************************************************************************************************
* Changelog:
*
* 0.1.5 Added portal and reso counter and reso details (Thanks BJT)
* 0.1.4 Added focus link in the toolbox. Some renaming. Removed div to use sidebar style.
* 0.1.3 Effective player name (with wrong capitalization) if it finds some reso
* 0.1.2 Made nickname case insensitive
* 0.1.1 Added mouseover for portal location. Dirty hack to not show mousehover when the alert is fired.
* 0.1.0 First public release
*********************************************************************************************************/
// use own namespace for plugin
window.plugin.playersResonators = function() {};
window.plugin.playersResonators.findReso = function(playername) {
var s = "";
var portalSet = {};
var effectiveNick = "";
var portalCounter = 0;
var resoCounter = 0;
// Assuming there can be no agents with same nick with different lower/uppercase
var nickToFind = playername.toLowerCase();
$.each(window.portals, function(ind, portal){
var resoLevels = {};
var r = portal.options.details.resonatorArray.resonators;
$.each(r, function(ind, reso) {
if (!reso) return true;
var nick = getPlayerName(reso.ownerGuid);
if (nick.toLowerCase() === nickToFind){
resoCounter += 1;
if (!effectiveNick) {
effectiveNick = nick;
}
if (reso.level in resoLevels){
resoLevels[reso.level] += 1;
} else {
resoLevels[reso.level] = 1;
}
if (!portalSet.hasOwnProperty(portal.options.guid)){
portalSet[portal.options.guid] = true;
var latlng = [portal.options.details.locationE6.latE6/1E6, portal.options.details.locationE6.lngE6/1E6].join();
var guid = portal.options.guid;
var zoomPortal = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.options.details.locationE6.latE6+'&lngE6='+portal.options.details.locationE6.lngE6+'&z=17&pguid='+guid;
var a = $('<a>',{
"class": 'help',
text: portal.options.details.portalV2.descriptiveText.TITLE,
title: portal.options.details.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: zoomPortal
})[0].outerHTML;
portalCounter += 1;
s += a + ": ";
}
}
});
if (portalSet.hasOwnProperty(portal.options.guid)){
for (var i = 8; i>0; i--){
if (i in resoLevels)
s += resoLevels[i] + "xL" + i + " ";
}
s += "\n";
}
});
if (s) {
// Showing the playername as a "fake" link to avoid the auto-mouseover effect on the first portal
fakeLinkPlayer = '<a href="#" onClick="return false;">' + effectiveNick + '</a>'
s = fakeLinkPlayer + " has " + resoCounter + " resonators on " + portalCounter + " portals:\n\n" + s;
} else {
s = playername + " has no resonators in this range\n";
}
alert(s);
}
var setup = function() {
var content = '<input id="playerReso" placeholder="Type player name to find resonators..." type="text">';
$('#sidebar').append(content);
$('#toolbox').append(' <a onclick=$("#playerReso").focus() title="Find all portals with resonators of a certain player">Player\'s Reso</a>');
$("#playerReso").keypress(function(e) {
if((e.keyCode ? e.keyCode : e.which) !== 13) return;
var data = $(this).val();
window.plugin.playersResonators.findReso(data);
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-portals-count@yenky
// @name IITC plugin: Show total counts of portals
// @category Info
// @version 0.0.8.@@DATETIMEVERSION@@
// @version 0.0.9.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -50,9 +50,8 @@ window.plugin.portalcounts.getPortals = function(){
$.each(window.portals, function(i, portal) {
retval=true;
var d = portal.options.details;
var level = portal.options.level;
var team = portal.options.team;
var level = Math.floor(getPortalLevel(d));
// just count portals in viewport
if(!displayBounds.contains(portal.getLatLng())) return true;
switch (team){
@ -84,15 +83,16 @@ window.plugin.portalcounts.getPortals = function(){
counts += '<td class="enl">'+window.plugin.portalcounts.PortalsEnl[level]+'</td><td class="res">'+window.plugin.portalcounts.PortalsRes[level]+'</td>';
counts += '</tr>';
}
counts += '<tr><td colspan="3">&nbsp</td></tr>';
counts += '<tr><th>Total:</th><td class="enl">'+window.plugin.portalcounts.enlP+'</td><td class="res">'+window.plugin.portalcounts.resP+'</td></tr>';
counts += '<tr><td>Neutral:</td><td colspan="2">';
if(minlvl > 0)
counts += 'zoom in to see unclaimed';
counts += 'zoom in to see unclaimed portals';
else
counts += window.plugin.portalcounts.neuP;
counts += ' Portal(s)</td></tr>';
counts += '<tr class="enl"><th colspan="2">Enlightened:</th><td>'+window.plugin.portalcounts.enlP+' Portal(s)</td></tr>';
counts += '<tr class="res"><th colspan="2">Resistance:</th><td>'+window.plugin.portalcounts.resP+' Portal(s)</td></tr>';
counts += '</td></tr>';
} else
counts += '<tr><td>No Portals in range!</td></tr>';
counts += '</table>';

View File

@ -1,17 +1,18 @@
// ==UserScript==
// @id iitc-plugin-defense@gluckies
// @name IITC plugin: portal defense
// @category Layer
// @category Deleted
// @version 0.2.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Shows the defense values of every portal (see also "hightlight portals total mitigation" highlighter)
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// ==/UserScript==
<<<<<<< HEAD
@@PLUGINSTART@@
@ -169,3 +170,5 @@ var setup = function() {
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@
=======
>>>>>>> 68ec278914ced792f20cbd133f9481d6078435a6

View File

@ -1,49 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-bad-deployment-distance@cathesaurus
// @name IITC plugin: highlight badly-deployed portals
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show the effective resonator deployment range, where that average is less than 36 metres
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterBadDeploymentDistance = function() {};
window.plugin.portalHighlighterBadDeploymentDistance.highlight = function(data) {
var d = data.portal.options.details;
var portal_deployment = 0;
if(getTeam(d) !== 0) {
var avgDist = window.getAvgResoDist(d);
if(avgDist > 0 && avgDist < window.HACK_RANGE*0.9) {
portal_deployment = (window.HACK_RANGE - avgDist)/window.HACK_RANGE;
}
if(portal_deployment > 0) {
var fill_opacity = portal_deployment*.85 + .15;
// magenta for *exceptionally* close deployments (spoofing? under 1m average), then shades of
// red, orange and yellow for further out
color = avgDist < 1 ? 'magenta' : avgDist < (window.HACK_RANGE*.25) ? 'red' : avgDist < (window.HACK_RANGE*.6) ? 'orange' : 'yellow';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
}
var setup = function() {
window.addPortalHighlighter('Bad Deployment Distance', window.plugin.portalHighlighterBadDeploymentDistance.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,74 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-upgrade@vita10gy
// @name IITC plugin: highlight portals you can upgrade to a specific level
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to highlight portals you can upgrade to a specific level.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalsCanMakeLevel = function() {};
window.plugin.portalHighligherPortalsCanMakeLevel.highlight = function(data,highlight_level) {
var d = data.portal.options.details;
var current_level = Math.floor(getPortalLevel(d));
var potential_level = Math.floor(window.potentialPortalLevel(d));
var opacity = .7;
if( potential_level > current_level && potential_level === highlight_level) {
color = 'red';
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
//determines the level of poral a user can make all on their own
window.plugin.portalHighligherPortalsCanMakeLevel.playerCanSoloLevel = function(lvl) {
var resonators_total = 0;
var resonators_placed = 0;
var resonator_level = PLAYER.level
while(resonators_placed < 8) {
for(var i = 0; i<MAX_RESO_PER_PLAYER[resonator_level]; i++) {
if(resonators_placed < 8) {
resonators_total += resonator_level;
resonators_placed++;
}
}
resonator_level--;
}
return(Math.floor(resonators_total/8));
}
window.plugin.portalHighligherPortalsCanMakeLevel.getHighlighter = function(lvl) {
return(function(data){
window.plugin.portalHighligherPortalsCanMakeLevel.highlight(data,lvl);
});
}
var setup = function() {
// This is the maximum level of a portal a user can be the "last piece of"
// yes, even a level 1 can be the difference in bumping a portal up to level 7
var max_can_complete = 7;
if(PLAYER.level === 8) {
max_can_complete = 8;
}
// The rational behind the "minimum" level below is that showing a level 7 player, for example, all the portals they can make
// a level 5 would be silly, as they can make ANY portal a level 5.
for(var ptl_lvl = window.plugin.portalHighligherPortalsCanMakeLevel.playerCanSoloLevel()+1; ptl_lvl<=max_can_complete; ptl_lvl++) {
window.addPortalHighlighter('Can Make Level ' + ptl_lvl, window.plugin.portalHighligherPortalsCanMakeLevel.getHighlighter(ptl_lvl));
}
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,64 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-imminent-decay@cathesaurus
// @name IITC plugin: highlight portals with resonators about to decay
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show resonators due to decay within the next day. Red = portal will decay completely, orange = portal will drop all links, yellow = one or more resonators will decay completely.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterImminentDecay = function() {};
window.plugin.portalHighlighterImminentDecay.highlight = function(data) {
var d = data.portal.options.details;
if(getTeam(d) !== 0) {
//Check the energy of every resonator.
var resImminentDecayCount = 0;
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null) {
var level = parseInt(reso.level);
var maxResonatorEnergy = window.RESO_NRG[level];
var currentResonatorEnergy = parseInt(reso.energyTotal);
if((currentResonatorEnergy / maxResonatorEnergy) < 0.15) {
resImminentDecayCount++;
}
resCount++;
}
});
if(resImminentDecayCount > 0) {
if(resImminentDecayCount === resCount) {
var color = 'red';
} else if((resCount - resImminentDecayCount) < 3) {
color = 'orange';
} else {
color = 'yellow';
}
// Apply colour to portal.
var params = {fillColor: color, fillOpacity: 1};
data.portal.setStyle(params);
}
}
window.COLOR_SELECTED_PORTAL = '#f0f';
}
var setup = function() {
window.addPortalHighlighter('Imminent Decay', window.plugin.portalHighlighterImminentDecay.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-highlight-portal-infrastructure@vita10gy
// @name IITC plugin: highlight portals with infrastructure problems
// @category Highlighter
// @version 0.2.0.@@DATETIMEVERSION@@
// @version 0.2.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -31,15 +31,15 @@ window.plugin.portalInfrastructure.badTitles = ['^statue$',
'no title'];
window.plugin.portalInfrastructure.highlight = function(data) {
var d = data.portal.options.details;
var d = data.portal.options.data;
var color = '';
var opa = .75;
if(!(d.imageByUrl && d.imageByUrl.imageUrl)) {
if(!(d.image)) {
color = 'red';
}
if((new RegExp(window.plugin.portalInfrastructure.badTitles.join("|"),'i')).test(d.portalV2.descriptiveText.TITLE)) {
if((new RegExp(window.plugin.portalInfrastructure.badTitles.join("|"),'i')).test(d.title)) {
color = color == 'red' ? 'orange' : 'yellow';
opa = .9;
}

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-highlight-portals-level-color@vita10gy
// @name IITC plugin: highlight portals by level color
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @version 0.1.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -22,8 +22,7 @@
window.plugin.portalHighligherPortalsLevelColor = function() {};
window.plugin.portalHighligherPortalsLevelColor.colorLevel = function(data) {
var d = data.portal.options.details;
var portal_level = Math.floor(getPortalLevel(d));
var portal_level = data.portal.options.data.level;
var opacity = .6;
data.portal.setStyle({fillColor: COLORS_LVL[portal_level], fillOpacity: opacity});
}

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-highlight-portals-missing-resonators@vita10gy
// @name IITC plugin: highlight portals missing resonators
// @category Highlighter
// @version 0.1.1.@@DATETIMEVERSION@@
// @version 0.1.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -22,29 +22,19 @@
window.plugin.portalsMissingResonators = function() {};
window.plugin.portalsMissingResonators.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
//Ding the portal for every missing resonator.
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso === null) {
portal_weakness += .125;
} else {
resCount++;
}
});
if(portal_weakness > 0) {
var fill_opacity = portal_weakness*.85 + .15;
if(data.portal.options.team != TEAM_NONE) {
var res_count = data.portal.options.data.resCount;
if(res_count < 8) {
var fill_opacity = ((8-res_count)/8)*.85 + .15;
var color = 'red';
fill_opacity = Math.round(fill_opacity*100)/100;
var params = {fillColor: color, fillOpacity: fill_opacity};
if(resCount < 8) {
// Hole per missing resonator
var dash = new Array(8-resCount + 1).join("1,4,") + "100,0"
params["dashArray"] = dash;
}
// Hole per missing resonator
var dash = new Array((8 - res_count) + 1).join("1,4,") + "100,0"
params.dashArray = dash;
data.portal.setStyle(params);
}
}

View File

@ -1,48 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-mitigation@jonatkins
// @name IITC plugin: hightlight portals total mitigation
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show mitigation. Shades of red to the maximum of 95, then tints towards purple for over 95
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMitigation = function() {};
window.plugin.portalHighligherMitigation.highlight = function(data) {
var defense = window.getPortalMitigationDetails(data.portal.options.details);
if (defense.total > 0) {
var fill_opacity = (defense.total/95)*.85 + .15;
var blue = Math.max(0,Math.min(255,Math.round(defense.excess/80*255)));
var colour = 'rgb(255,0,'+blue+')';
var params = {fillColor: colour, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
var setup = function() {
window.addPortalHighlighter('Mitigation (defense)', window.plugin.portalHighligherMitigation.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,103 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-mods@vita10gy
// @name IITC plugin: highlight portal mods
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote if the portal has the selected mod.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMods = function() {};
window.plugin.portalHighligherMods.highlight = function(data, mod_type) {
var d = data.portal.options.details;
if(!jQuery.isArray(mod_type)) {
mod_type = [mod_type];
}
var mod_effect = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null && jQuery.inArray(mod.type, mod_type) > -1) {
switch(mod.rarity){
case 'COMMON':
mod_effect++;
break;
case 'RARE':
mod_effect+=2;
break;
case 'VERY_RARE':
mod_effect+=3;
break;
}
}
});
if(mod_effect > 0) {
var fill_opacity = mod_effect/12*.8 + .2;
var color = 'red';
fill_opacity = Math.round(fill_opacity*100)/100;
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
window.plugin.portalHighligherMods.highlightNoMods = function(data) {
var d = data.portal.options.details;
var mods = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null) {
mods += 1;
}
});
if(mods == 0) {
var fill_opacity = .6;
var color = 'red';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
} else if(mods <4) {
var fill_opacity = .6;
var color = 'yellow';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
window.plugin.portalHighligherMods.getHighlighter = function(type) {
return(function(data){
window.plugin.portalHighligherMods.highlight(data,type);
});
}
var setup = function() {
$.each(MOD_TYPE, function(ind, name){
window.addPortalHighlighter('Mod: '+name, window.plugin.portalHighligherMods.getHighlighter(ind));
});
window.addPortalHighlighter('Mod: Hackability', window.plugin.portalHighligherMods.getHighlighter(['MULTIHACK', 'HEATSINK']));
window.addPortalHighlighter('Mod: Attack', window.plugin.portalHighligherMods.getHighlighter(['FORCE_AMP', 'TURRET']));
window.addPortalHighlighter('Mod: Defense', window.plugin.portalHighligherMods.getHighlighter(['RES_SHIELD', 'FORCE_AMP', 'TURRET']));
window.addPortalHighlighter('Mod: None', window.plugin.portalHighligherMods.highlightNoMods);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,53 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-my-8-portals@vita10gy
// @name IITC plugin: highlight my level 8's on portals
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote portals you have a level 8 on.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMy8sOnPortals = function() {};
window.plugin.portalHighligherMy8sOnPortals.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
var color = 'red';
var opacity = .7;
var resCount = false;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null && reso.ownerGuid === PLAYER.guid && reso.level == 8) {
resCount = true;
}
});
if(resCount) {
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
}
var setup = function() {
//Don't list it if it isn't applicable yet
if(PLAYER.level == 8) {
window.addPortalHighlighter('My Level 8 Resonators', window.plugin.portalHighligherMy8sOnPortals.highlight);
}
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,70 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-my-portals@vita10gy
// @name IITC plugin: highlight my portals
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote portals you have a hand in. Orange is just ownership. Yellow is shields. Red is Resonators. Red trumps both, yellow trumps orange.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherMyPortals = function() {};
window.plugin.portalHighligherMyPortals.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
var color = '';
var opacity = .7;
if(PLAYER.guid === d.captured.capturingPlayerId) {
color = 'orange';
}
var modCount = 0;
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null && mod.installingUser === PLAYER.guid) {
color = 'yellow';
modCount++;
}
});
if(modCount > 0) {
opacity = modCount*.25*.7 + .3;
}
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso !== null && reso.ownerGuid === PLAYER.guid) {
color = 'red';
resCount++;
}
});
if(resCount > 0) {
opacity = resCount*.125*.7 + .3;
}
if(color !== '') {
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
}
var setup = function() {
window.addPortalHighlighter('My Portals', window.plugin.portalHighligherMyPortals.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,11 +2,11 @@
// @id iitc-plugin-highlight-needs-recharge@vita10gy
// @name IITC plugin: hightlight portals that need recharging
// @category Highlighter
// @version 0.1.0.@@DATETIMEVERSION@@
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote if the portal needs recharging
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote if the portal needs recharging. Colours also indicate severity: yellow: above 85%, orange: above 50%, red: above 15%, magenta: below 15%
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
@ -22,23 +22,23 @@
window.plugin.portalHighligherNeedsRecharge = function() {};
window.plugin.portalHighligherNeedsRecharge.highlight = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
if(window.getTotalPortalEnergy(d) > 0 && window.getCurrentPortalEnergy(d) < window.getTotalPortalEnergy(d)) {
portal_weakness = 1 - (window.getCurrentPortalEnergy(d)/window.getTotalPortalEnergy(d));
}
if(portal_weakness > 0) {
var fill_opacity = portal_weakness*.85 + .15;
color = 'red';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
var d = data.portal.options.data;
var portal_health = d.health/100;
if(data.portal.options.team != TEAM_NONE && portal_health < 1) {
var fill_opacity = (1-portal_health)*.85 + .15;
var color;
if (portal_health > .85) color = 'yellow';
else if (portal_health > .5) color = 'orange';
else if (portal_health > .15) color = 'red';
else color = 'magenta';
var params = {fillColor: color, fillOpacity: fill_opacity};
data.portal.setStyle(params);
}
}
var setup = function() {
window.addPortalHighlighter('Needs Recharge', window.plugin.portalHighligherNeedsRecharge.highlight);
window.addPortalHighlighter('Needs Recharge (Health)', window.plugin.portalHighligherNeedsRecharge.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////

View File

@ -1,63 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-outbound-link-counter@cathesaurus
// @name IITC plugin: highlight portals running low on outbound links
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to show the number of outbound links: red = 8 (i.e. no more outbound links may be made), orange = 6 or 7, yellow = 4 or 5.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighlighterOutboundLinkCounter = function() {};
window.plugin.portalHighlighterOutboundLinkCounter.highlight = function(data) {
var d = data.portal.options.details;
var outgoing = 0;
var playerFaction = 0;
if (window.PLAYER.team === 'RESISTANCE') {
playerFaction = window.TEAM_RES;
} else {
playerFaction = window.TEAM_ENL;
}
// Only interested in portals of player's faction
if(getTeam(d) === playerFaction) {
if(d.portalV2.linkedEdges) $.each(d.portalV2.linkedEdges, function(ind, link) {
if (link.isOrigin) {
outgoing++;
}
});
if(outgoing > 3) {
if(outgoing < 6) {
color = 'yellow';
} else if(outgoing < 8) {
color = 'orange';
} else {
color = 'red';
}
var params = {fillColor: color, fillOpacity: 1};
data.portal.setStyle(params);
}
}
}
var setup = function() {
window.addPortalHighlighter('Outbound Links', window.plugin.portalHighlighterOutboundLinkCounter.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,104 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap-by-energy-relative@vita10gy
// @name IITC plugin: highlight portals by ap/energy (relative)
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP/Energy value relative to what's currently on the screen. Brighter is better. Orange means your standard 8 down 8 up swap.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAPPerEnergyRelative = function() {};
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = null;
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = null;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAPPerEnergyRelative.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAPPerEnergyRelative.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP == null ||
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP == null) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.calculateAPLevels();
}
var minApE = window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP;
var maxApE = window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP;
if(PLAYER.team !== d.controllingTeam.team) {
var ap = getAttackApGain(d);
var energy = getCurrentPortalEnergy(d);
if(energy < 1) {
energy = 1;
}
portal_ap = ap.enemyAp;
var opacity = 1;
if(minApE !== maxApE) {
opacity = ((ap.enemyAp / energy) - minApE) / (maxApE - minApE);
}
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
window.plugin.portalHighligherPortalAPPerEnergyRelative.resetAPLevels = function() {
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = null;
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = null;
}
window.plugin.portalHighligherPortalAPPerEnergyRelative.calculateAPLevels = function() {
var displayBounds = map.getBounds();
$.each(window.portals, function(qk, portal) {
if(displayBounds.contains(portal.getLatLng())) {
if(PLAYER.team !== portal.options.details.controllingTeam.team) {
var ap = getAttackApGain(portal.options.details);
var energy = getCurrentPortalEnergy(portal.options.details);
if(energy < 1) {
energy = 1;
}
var portal_ap = ap.enemyAp / energy;
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP === null ||
portal_ap < window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.minAP = portal_ap;
}
if(window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP === null ||
portal_ap > window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP) {
window.plugin.portalHighligherPortalAPPerEnergyRelative.maxAP = portal_ap;
}
}
}
});
}
var setup = function() {
window.addPortalHighlighter('AP/Energy (Relative)', window.plugin.portalHighligherPortalAPPerEnergyRelative.highlight);
window.addHook('requestFinished', window.plugin.portalHighligherPortalAPPerEnergyRelative.resetAPLevels);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,99 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap-relative@vita10gy
// @name IITC plugin: highlight portals by ap relative
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP value relative to what's currently on the screen. Brighter is better. Orange means your standard 8 down 8 up swap.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAPRelative = function() {};
window.plugin.portalHighligherPortalAPRelative.minAP = null;
window.plugin.portalHighligherPortalAPRelative.maxAP = null;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAPRelative.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAPRelative.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
if(window.plugin.portalHighligherPortalAPRelative.minAP == null ||
window.plugin.portalHighligherPortalAPRelative.maxAP == null) {
window.plugin.portalHighligherPortalAPRelative.calculateAPLevels();
}
var minAp = window.plugin.portalHighligherPortalAPRelative.minAP;
var maxAp = window.plugin.portalHighligherPortalAPRelative.maxAP;
var ap = getAttackApGain(d);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== d.controllingTeam.team) {
portal_ap = ap.enemyAp;
if(portal_ap === window.plugin.portalHighligherPortalAPRelative.baseSwapAP) {
color = 'orange';
}
}
var opacity = 1;
if(minAp !== maxAp) {
opacity = (portal_ap - minAp) / (maxAp - minAp);
}
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
window.plugin.portalHighligherPortalAPRelative.resetAPLevels = function() {
window.plugin.portalHighligherPortalAPRelative.minAP = null;
window.plugin.portalHighligherPortalAPRelative.maxAP = null;
}
window.plugin.portalHighligherPortalAPRelative.calculateAPLevels = function() {
var displayBounds = map.getBounds();
$.each(window.portals, function(qk, portal) {
if(displayBounds.contains(portal.getLatLng())) {
var ap = getAttackApGain(portal.options.details);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== portal.options.details.controllingTeam.team) {
portal_ap = ap.enemyAp;
}
if(window.plugin.portalHighligherPortalAPRelative.minAP === null ||
portal_ap < window.plugin.portalHighligherPortalAPRelative.minAP) {
window.plugin.portalHighligherPortalAPRelative.minAP = portal_ap;
}
if(window.plugin.portalHighligherPortalAPRelative.maxAP === null ||
portal_ap > window.plugin.portalHighligherPortalAPRelative.maxAP) {
window.plugin.portalHighligherPortalAPRelative.maxAP = portal_ap;
}
}
});
}
var setup = function() {
window.addPortalHighlighter('AP (Relative)', window.plugin.portalHighligherPortalAPRelative.highlight);
window.addHook('requestFinished', window.plugin.portalHighligherPortalAPRelative.resetAPLevels);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,60 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-by-ap@vita10gy
// @name IITC plugin: highlight portals by ap
// @category Highlighter
// @category Deleted
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill color of the portals to denote AP value. Brighter is better. Orange means your standard 8 down 8 up swap.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalAP = function() {};
window.plugin.portalHighligherPortalAP.minAP = 65;
//Anything over max AP will be 100% opacity.
window.plugin.portalHighligherPortalAP.maxAP = 6000;
//This is the AP for a run of the mill takedown/putback
window.plugin.portalHighligherPortalAP.baseSwapAP = 2350;
window.plugin.portalHighligherPortalAP.highlight = function(data) {
var d = data.portal.options.details;
var color = 'red';
var ap = getAttackApGain(d);
var portal_ap = ap.friendlyAp;
if(PLAYER.team !== d.controllingTeam.team) {
portal_ap = ap.enemyAp;
if(portal_ap === window.plugin.portalHighligherPortalAP.baseSwapAP) {
color = 'orange';
}
}
var opacity = (portal_ap - window.plugin.portalHighligherPortalAP.minAP) / window.plugin.portalHighligherPortalAP.maxAP;
if(opacity < 0) {
opacity = 0;
}
if(opacity > 1) {
opacity = 1;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
var setup = function() {
window.addPortalHighlighter('AP (Static)', window.plugin.portalHighligherPortalAP.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -31,8 +31,7 @@ window.plugin.portalHighligherPortalsMyLevel.aboveLevel = function(data) {
}
window.plugin.portalHighligherPortalsMyLevel.colorLevel = function(below,data) {
var d = data.portal.options.details;
var portal_level = Math.floor(getPortalLevel(d));
var portal_level = data.portal.options.level;
var player_level = PLAYER.level;
var opacity = .6;
if((below && portal_level <= player_level) ||

View File

@ -1,80 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-upgrade@vita10gy
// @name IITC plugin: highlight portals you can upgrade
// @category Highlighter
// @category Deleted
// @version 0.2.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Upgradable - Yellow: you can upgrade it at all. Orange: you can change the level. Red: you can make it your level or higher. To Elite: Yellow - To Level 6. Orange - To Level 7. Red - To Level 8.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalHighligherPortalsUpgrade = function() {};
window.plugin.portalHighligherPortalsUpgrade.highlight = function(data) {
var d = data.portal.options.details;
var current_level = getPortalLevel(d);
var potential_level = window.potentialPortalLevel(d);
var player_level = PLAYER.level;
var opacity = .7;
if( potential_level > current_level) {
potential_level = Math.floor(potential_level);
current_level = Math.floor(current_level);
//console.log(potential_level + '>' + current_level);
var color = 'yellow';
if(potential_level > current_level) {
color = 'orange';
if(potential_level >= player_level) {
color = 'red';
}
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
window.plugin.portalHighligherPortalsUpgrade.highlight_elite = function(data) {
var d = data.portal.options.details;
var current_level = getPortalLevel(d);
var potential_level = window.potentialPortalLevel(d);
var opacity = .8;
var color = '';
potential_level = Math.floor(potential_level);
current_level = Math.floor(current_level);
if( potential_level > current_level && potential_level >= 6) {
switch(potential_level) {
case 6:
color = 'yellow';
break;
case 7:
color = 'orange';
break;
case 8:
color = 'red';
opacity = .9;
break;
}
data.portal.setStyle({fillColor: color, fillOpacity: opacity});
}
}
var setup = function() {
window.addPortalHighlighter('Upgradable', window.plugin.portalHighligherPortalsUpgrade.highlight);
window.addPortalHighlighter('Upgradable to Elite', window.plugin.portalHighligherPortalsUpgrade.highlight_elite);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,54 +1,15 @@
// ==UserScript==
// @id iitc-plugin-highlight-portals-with-L8-resonators@superd
// @name IITC plugin: highlight portals with L8 resonators
// @category Highlighter
// @category Deleted
// @version 0.1.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Uses the fill red of the portals, if portal has L8 res
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.portalsWithL8Resonators = function() {};
window.plugin.portalsWithL8Resonators.highlight = function(data) {
var d = data.portal.options.details;
var has_L8 = 0;
if(getTeam(d) !== 0) {
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso) {
var level = parseInt(reso.level);
if(level == 8)
{
has_L8+=1;
}
}
});
}
if(has_L8 > 0)
{
var color = 'red';
var opa = has_L8 * 0.125;
var params = {fillColor: color, fillOpacity: opa};
data.portal.setStyle(params);
}
}
var setup = function() {
window.addPortalHighlighter('Portals with L8 Resonators', window.plugin.portalsWithL8Resonators.highlight);
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-portal-level-numbers@rongou
// @name IITC plugin: Portal Level Numbers
// @category Layer
// @version 0.1.1.@@DATETIMEVERSION@@
// @version 0.1.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -38,8 +38,8 @@ window.plugin.portalLevelNumbers.portalAdded = function(data) {
window.plugin.portalLevelNumbers.renderLevel = function(guid,latLng) {
plugin.portalLevelNumbers.removeLevel(guid);
var d = window.portals[guid].options.details;
var levelNumber = Math.floor(window.getPortalLevel(d));
var p = window.portals[guid];
var levelNumber = p.options.level;
var level = L.marker(latLng, {
icon: L.divIcon({
className: 'plugin-portal-level-numbers',

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-portal-names@zaso
// @name IITC plugin: Portal Names
// @category Layer
// @version 0.1.2.@@DATETIMEVERSION@@
// @version 0.1.3.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -63,8 +63,8 @@ window.plugin.portalNames.addLabel = function(guid, latLng) {
var previousLayer = window.plugin.portalNames.labelLayers[guid];
if (!previousLayer) {
var d = window.portals[guid].options.details;
var portalName = d.portalV2.descriptiveText.TITLE;
var d = window.portals[guid].options.data;
var portalName = d.title;
var label = L.marker(latLng, {
icon: L.divIcon({

View File

@ -1,453 +1,15 @@
// ==UserScript==
// @id iitc-plugin-portals-list@teo96
// @name IITC plugin: show list of portals
// @category Info
// @category Deleted
// @version 0.0.18.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] Display a sortable list of all visible portals with full details about the team, resonators, shields, etc.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
/* whatsnew
* 0.0.15: Add 'age' column to display how long each portal has been controlled by its current owner.
* 0.0.14: Add support to new mods (S:Shield - T:Turret - LA:Link Amp - H:Heat-sink - M:Multi-hack - FA:Force Amp)
* 0.0.12: Use dialog() instead of alert so the user can drag the box around
* 0.0.11: Add nominal energy column and # links, fix sort bug when opened even amounts of times, nits
* 0.0.10: Fixed persistent css problem with alert
* 0.0.9 : bugs hunt
* 0.0.8 : Aborted to avoid problems with Niantic (export portals informations as csv or kml file)
* 0.0.7 : more informations available via tooltips (who deployed, energy, ...), new E/AP column
* 0.0.6 : Add power charge information into a new column + bugfix
* 0.0.5 : Filter portals by clicking on 'All portals', 'Res Portals' or 'Enl Portals'
* 0.0.4 : Add link to portals name, one click to display full information in portal panel, double click to zoom on portal, hover to show address
* 0.0.3 : sorting ascending/descending and add numbers of portals by faction on top on table
* 0.0.2 : add sorting feature when click on header column
* 0.0.1 : initial release, show list of portals with level, team, resonators and shield information
*
* Display code inspired from @vita10gy's scoreboard plugin : iitc-plugin-scoreboard@vita10gy - https://github.com/breunigs/ingress-intel-total-conversion
* Portal link code from xelio - iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
*
* todo : export as GPX, Open in Google Maps, more statistics in the header, what else ?
*/
// use own namespace for plugin
window.plugin.portalslist = function() {};
window.plugin.portalslist.listPortals = []; // structure : name, team, level, resonators = Array, Shields = Array, APgain, Age
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
window.plugin.portalslist.filter=0;
//fill the listPortals array with portals avaliable on the map (level filtered portals will not appear in the table)
window.plugin.portalslist.getPortals = function() {
//filter : 0 = All, 1 = Res, 2 = Enl
//console.log('** getPortals');
var retval=false;
var displayBounds = map.getBounds();
window.plugin.portalslist.listPortals = [];
//get portals informations from IITC
$.each(window.portals, function(i, portal) {
// eliminate offscreen portals (selected, and in padding)
if(!displayBounds.contains(portal.getLatLng())) return true;
retval=true;
var d = portal.options.details;
var name = d.portalV2.descriptiveText.TITLE;
var address = d.portalV2.descriptiveText.ADDRESS;
var img = getPortalImageUrl(d);
var team = portal.options.team;
var now = new Date();
var now_ms = now.getTime();// + (now.getTimezoneOffset() * 60000);
var age_in_seconds = 0;
var age_string_long = 'This portal is not captured.';
var age_string_short = 'n/a';
if(portal.options.details.hasOwnProperty('captured') && portal.options.details.captured.hasOwnProperty('capturedTime')) {
var age_in_seconds = Math.floor((now_ms - portal.options.details.captured.capturedTime)/1000);
var age_string_long = window.plugin.portalslist.secondsToString(age_in_seconds, 'l');
var age_string_short = window.plugin.portalslist.secondsToString(age_in_seconds, 's');
}
switch (team){
case 1 :
window.plugin.portalslist.resP++;
break;
case 2 :
window.plugin.portalslist.enlP++;
break;
}
var level = getPortalLevel(d).toFixed(2);
var guid = portal.options.guid;
//get resonators informations
var resonators = []; // my local resonator array : reso level, reso deployed by, distance to portal, energy total, max
var energy = 0;
var maxenergy=0;
$.each(portal.options.details.resonatorArray.resonators, function(ind, reso) {
if(reso) {
resonators[ind] = [reso.level, window.getPlayerName(reso.ownerGuid), reso.distanceToPortal, reso.energyTotal, RESO_NRG[reso.level]];
energy += reso.energyTotal;
maxenergy += RESO_NRG[reso.level];
} else { resonators[ind] = [0,'',0,0,0]; }
});
// Sort resonators array by resonator level
resonators.sort(function (a, b) {return b[0] - a[0]});
//get mods informations
var mods = [];
$.each(d.portalV2.linkedModArray, function(ind, mod) {
var modShortName='';
if (mod) {
switch (mod.displayName) {
case 'Portal Shield':
modShortName = 'S';
break;
case 'Force Amp':
modShortName = 'FA';
break;
case 'Link Amp':
modShortName = 'LA';
break;
case 'Heat Sink':
modShortName = 'H';
break;
case 'Multi-hack':
modShortName = 'M';
break;
case 'Turret':
modShortName = 'T';
break;
default:
modShortName = '';
break;
}
if (modShortName === '') {
mods[ind] = ['', '', ''];
} else {
if ((modShortName === 'S') &&
((mod.rarity=='COMMON' && mod.stats.MITIGATION == 6) ||
(mod.rarity=='RARE' && mod.stats.MITIGATION == 8) ||
(mod.rarity=='VERY_RARE' && mod.stats.MITIGATION == 10)))
modShortName=modShortName+'!';
mods[ind] = [mod.rarity, getPlayerName(mod.installingUser), modShortName, mod.displayName];
}
}else { mods[ind] = ['', '', '']; }
});
var APgain= getAttackApGain(d).enemyAp;
var thisPortal = {'portal': d,
'name': name,
'team': team,
'level': level,
'guid': guid,
'resonators': resonators,
'energyratio': maxenergy ? Math.floor(energy/maxenergy*100) : 0,
'mods': mods,
'APgain': APgain,
'EAP': (energy/APgain).toFixed(2),
'energy': energy,
'maxenergy': maxenergy,
'links': d.portalV2.linkedEdges.length,
'lat': portal._latlng.lat,
'lng': portal._latlng.lng,
'address': address,
'img': img,
'age': age_in_seconds,
'age_string_long': age_string_long,
'age_string_short': age_string_short};
window.plugin.portalslist.listPortals.push(thisPortal);
});
return retval;
}
window.plugin.portalslist.displayPL = function() {
// debug tools
//var start = new Date().getTime();
//console.log('***** Start ' + start);
var html = '';
window.plugin.portalslist.sortOrder=-1;
window.plugin.portalslist.enlP = 0;
window.plugin.portalslist.resP = 0;
if (window.plugin.portalslist.getPortals()) {
html += window.plugin.portalslist.portalTable('level', window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter);
} else {
html = '<table><tr><td>Nothing to show!</td></tr></table>';
};
dialog({
html: '<div id="portalslist">' + html + '</div>',
dialogClass: 'ui-dialog-portalslist',
title: 'Portal list: ' + window.plugin.portalslist.listPortals.length + ' ' + (window.plugin.portalslist.listPortals.length == 1 ? 'portal' : 'portals'),
id: 'portal-list',
width: 800
});
//run the name resolving process
resolvePlayerNames();
//debug tools
//end = new Date().getTime();
//console.log('***** end : ' + end + ' and Elapse : ' + (end - start));
}
window.plugin.portalslist.portalTable = function(sortBy, sortOrder, filter) {
// sortOrder <0 ==> desc, >0 ==> asc, i use sortOrder * -1 to change the state
window.plugin.portalslist.filter=filter;
var portals=window.plugin.portalslist.listPortals;
//Array sort
window.plugin.portalslist.listPortals.sort(function(a, b) {
var retVal = 0;
switch (sortBy) {
case 'names':
retVal = a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
break;
case 'r1':
retVal = b.resonators[0][0] - a.resonators[0][0];
if (retVal)
break;
case 'r2':
retVal = b.resonators[1][0] - a.resonators[1][0];
if (retVal)
break;
case 'r3':
retVal = b.resonators[2][0] - a.resonators[2][0];
if (retVal)
break;
case 'r4':
retVal = b.resonators[3][0] - a.resonators[3][0];
if (retVal)
break;
case 'r5':
retVal = b.resonators[4][0] - a.resonators[4][0];
if (retVal)
break;
case 'r6':
retVal = b.resonators[5][0] - a.resonators[5][0];
if (retVal)
break;
case 'r7':
retVal = b.resonators[6][0] - a.resonators[6][0];
if (retVal)
break;
case 'r8':
retVal = b.resonators[7][0] - a.resonators[7][0];
break;
case 's1':
retVal = a.mods[0][2] > b.mods[0][2] ? -1 : 1;
break;
case 's2':
retVal = a.mods[1][2] > b.mods[1][2] ? -1 : 1;
break;
case 's3':
retVal = a.mods[2][2] > b.mods[2][2] ? -1 : 1;
break;
case 's4':
retVal = a.mods[3][2] > b.mods[3][2] ? -1 : 1;
break;
default:
retVal = b[sortBy] - a[sortBy];
break;
}
if (sortOrder > 0) retVal = -retVal; //thx @jonatkins
return retVal;
});
var sort = window.plugin.portalslist.portalTableSort;
var html = window.plugin.portalslist.stats();
html += '<table>'
+ '<tr><th ' + sort('names', sortBy, -1) + '>Portal</th>'
+ '<th ' + sort('level', sortBy, -1) + '>Level</th>'
+ '<th title="Team" ' + sort('team', sortBy, -1) + '>T</th>'
+ '<th ' + sort('r1', sortBy, -1) + '>R1</th>'
+ '<th ' + sort('r2', sortBy, -1) + '>R2</th>'
+ '<th ' + sort('r3', sortBy, -1) + '>R3</th>'
+ '<th ' + sort('r4', sortBy, -1) + '>R4</th>'
+ '<th ' + sort('r5', sortBy, -1) + '>R5</th>'
+ '<th ' + sort('r6', sortBy, -1) + '>R6</th>'
+ '<th ' + sort('r7', sortBy, -1) + '>R7</th>'
+ '<th ' + sort('r8', sortBy, -1) + '>R8</th>'
+ '<th ' + sort('energy', sortBy, -1) + '>Energy</th>'
+ '<th ' + sort('energyratio', sortBy, -1) + '>%</th>'
+ '<th ' + sort('links', sortBy, -1) + '>Links</th>'
+ '<th ' + sort('s1', sortBy, -1) + '>M1</th>'
+ '<th ' + sort('s2', sortBy, -1) + '>M2</th>'
+ '<th ' + sort('s3', sortBy, -1) + '>M3</th>'
+ '<th ' + sort('s4', sortBy, -1) + '>M4</th>'
+ '<th ' + sort('mitigation', sortBy, -1) + '>Mit.</th>'
+ '<th ' + sort('APgain', sortBy, -1) + '>AP Gain</th>'
+ '<th title="Energy / AP Gain ratio" ' + sort('EAP', sortBy, -1) + '>E/AP</th>'
+ '<th ' + sort('age', sortBy, -1) + '>Age</th></tr>';
$.each(portals, function(ind, portal) {
if (filter === 0 || filter === portal.team) {
html += '<tr class="' + (portal.team === 1 ? 'res' : (portal.team === 2 ? 'enl' : 'neutral')) + '">'
+ '<td style="">' + window.plugin.portalslist.getPortalLink(portal.portal, portal.guid) + '</td>'
+ '<td class="L' + Math.floor(portal.level) +'">' + portal.level + '</td>'
+ '<td style="text-align:center;">' + portal.team + '</td>';
var mitigationDetails = getPortalMitigationDetails(portal.portal);
portal.mitigation = mitigationDetails.total + mitigationDetails.excess;
var title;
var percent;
$.each([0, 1, 2, 3 ,4 ,5 ,6 ,7], function(ind, slot) {
percent = portal.resonators[slot][4] ? Math.floor(portal.resonators[slot][3]/portal.resonators[slot][4]*100) : 0;
title = 'title="owner: <b>' + portal.resonators[slot][1] + '</b><br>'
+ 'energy: ' + portal.resonators[slot][3] + ' / ' + portal.resonators[slot][4] + ' (' + percent + '%)<br>'
+ 'distance: ' + portal.resonators[slot][2] + 'm';
html += '<td class="L' + portal.resonators[slot][0] +'" ' + title + '">' + portal.resonators[slot][0] + '</td>';
});
html += '<td style="cursor:help" title="'+ portal.energy +'">' + prettyEnergy(portal.energy) + '</td>'
+ '<td style="cursor:help" title="' + portal.energy + ' / ' + portal.maxenergy +'">' + portal.energyratio + '%</td>'
+ '<td style="cursor:help" title="' + portal.links + '">' + portal.links + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[0][0]]+';" title="Mod : ' + portal.mods[0][3] + '\nInstalled by : ' + portal.mods[0][1] + '\nRarity : ' + portal.mods[0][0] + '">' + portal.mods[0][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[1][0]]+';" title="Mod : ' + portal.mods[1][3] + '\nInstalled by : ' + portal.mods[1][1] + '\nRarity : ' + portal.mods[1][0] + '">' + portal.mods[1][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[2][0]]+';" title="Mod : ' + portal.mods[2][3] + '\nInstalled by : ' + portal.mods[2][1] + '\nRarity : ' + portal.mods[2][0] + '">' + portal.mods[2][2] + '</td>'
+ '<td style="cursor:help; background-color: '+COLORS_MOD[portal.mods[3][0]]+';" title="Mod : ' + portal.mods[3][3] + '\nInstalled by : ' + portal.mods[3][1] + '\nRarity : ' + portal.mods[3][0] + '">' + portal.mods[3][2] + '</td>'
+ '<td>' + portal.mitigation + '</td>'
+ '<td>' + portal.APgain + '</td>'
+ '<td>' + portal.EAP + '</td>'
+ '<td style="cursor:help;" title="' + portal.age_string_long + '">' + portal.age_string_short + '</td>';
html+= '</tr>';
}
});
html += '</table>';
html += '<div class="disclaimer">Click on portals table headers to sort by that column. '
+ 'Click on <b>All Portals, Resistance Portals, Enlightened Portals</b> to filter<br>'
+ 'Thanks to @vita10gy & @xelio for their IITC plugins who inspired me. A <a href="https://plus.google.com/113965246471577467739">@teo96</a> production. Vive la Résistance !</div>';
window.plugin.portalslist.sortOrder = window.plugin.portalslist.sortOrder*-1;
return html;
}
window.plugin.portalslist.stats = function(sortBy) {
//console.log('** stats');
var html = '<table><tr>'
+ '<td class="filterAll" style="cursor:pointer" onclick="window.plugin.portalslist.portalTable(\'level\',-1,0)"><a href=""></a>All Portals : (click to filter)</td><td class="filterAll">' + window.plugin.portalslist.listPortals.length + '</td>'
+ '<td class="filterRes" style="cursor:pointer" class="sorted" onclick="window.plugin.portalslist.portalTable(\'level\',-1,1)">Resistance Portals : </td><td class="filterRes">' + window.plugin.portalslist.resP +' (' + Math.floor(window.plugin.portalslist.resP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '<td class="filterEnl" style="cursor:pointer" class="sorted" onclick="window.plugin.portalslist.portalTable(\'level\',-1,2)">Enlightened Portals : </td><td class="filterEnl">'+ window.plugin.portalslist.enlP +' (' + Math.floor(window.plugin.portalslist.enlP/window.plugin.portalslist.listPortals.length*100) + '%)</td>'
+ '</tr>'
+ '</table>';
return html;
}
// A little helper function so the above isn't so messy
window.plugin.portalslist.portalTableSort = function(name, by) {
var retVal = 'data-sort="' + name + '"';
if(name === by) {
retVal += ' class="sorted"';
}
return retVal;
};
// portal link - single click: select portal
// double click: zoom to and select portal
// hover: show address
// code from getPortalLink function by xelio from iitc: AP List - https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/ap-list.user.js
window.plugin.portalslist.getPortalLink = function(portal,guid) {
var latlng = [portal.locationE6.latE6/1E6, portal.locationE6.lngE6/1E6].join();
var jsSingleClick = 'window.renderPortalDetails(\''+guid+'\');return false';
var jsDoubleClick = 'window.zoomToAndShowPortal(\''+guid+'\', ['+latlng+']);return false';
var perma = '/intel?latE6='+portal.locationE6.latE6+'&lngE6='+portal.locationE6.lngE6+'&z=17&pguid='+guid;
//Use Jquery to create the link, which escape characters in TITLE and ADDRESS of portal
var a = $('<a>',{
"class": 'help',
text: portal.portalV2.descriptiveText.TITLE,
title: portal.portalV2.descriptiveText.ADDRESS,
href: perma,
onClick: jsSingleClick,
onDblClick: jsDoubleClick
})[0].outerHTML;
var div = '<div class="portalTitle">'+a+'</div>';
return div;
}
// length can be "s" or "l" for "short" or "long"
window.plugin.portalslist.secondsToString = function(seconds, length) {
var numdays = Math.floor(seconds / 86400);
var numhours = Math.floor((seconds % 86400) / 3600);
var numminutes = Math.floor(((seconds % 86400) % 3600) / 60);
var numseconds = ((seconds % 86400) % 3600) % 60;
if(length === "l") {
return numdays + " days " + numhours + " hours " + numminutes + " minutes " + numseconds + " seconds";
} else {
return numdays + "d" + numhours + "h";
}
}
var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.portalslist.displayPL()" title="Display a list of portals in the current view">Portals list</a>');
$('head').append('<style>' +
//style.css sets dialog max-width to 700px - override that here
// (the width: 800 parameter to dialog is NOT enough to override that css limit)
'#dialog-portal-list {max-width: 800px !important;}' +
'#portalslist table {margin-top:5px; border-collapse: collapse; empty-cells: show; width:100%; clear: both;}' +
'#portalslist table td, #portalslist table th {border-bottom: 1px solid #0b314e; padding:3px; color:white; background-color:#1b415e}' +
'#portalslist table tr.res td { background-color: #005684; }' +
'#portalslist table tr.enl td { background-color: #017f01; }' +
'#portalslist table tr.neutral td { background-color: #000000; }' +
'#portalslist table th { text-align: center;}' +
'#portalslist table td { text-align: center;}' +
'#portalslist table td.L0 { cursor: help; background-color: #000000 !important;}' +
'#portalslist table td.L1 { cursor: help; background-color: #FECE5A !important;}' +
'#portalslist table td.L2 { cursor: help; background-color: #FFA630 !important;}' +
'#portalslist table td.L3 { cursor: help; background-color: #FF7315 !important;}' +
'#portalslist table td.L4 { cursor: help; background-color: #E40000 !important;}' +
'#portalslist table td.L5 { cursor: help; background-color: #FD2992 !important;}' +
'#portalslist table td.L6 { cursor: help; background-color: #EB26CD !important;}' +
'#portalslist table td.L7 { cursor: help; background-color: #C124E0 !important;}' +
'#portalslist table td.L8 { cursor: help; background-color: #9627F4 !important;}' +
'#portalslist table td:nth-child(1) { text-align: left;}' +
'#portalslist table th { cursor:pointer; text-align: right;}' +
'#portalslist table th:nth-child(1) { text-align: left;}' +
'#portalslist table th.sorted { color:#FFCE00; }' +
'#portalslist .filterAll { margin-top: 10px;}' +
'#portalslist .filterRes { margin-top: 10px; background-color: #005684 }' +
'#portalslist .filterEnl { margin-top: 10px; background-color: #017f01 }' +
'#portalslist .disclaimer { margin-top: 10px; font-size:10px; }' +
'#portalslist .portalTitle { display: inline-block; width: 160px !important; min-width: 160px !important; max-width: 160px !important; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }' +
'</style>');
// Setup sorting
$(document).on('click.portalslist', '#portalslist table th', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,window.plugin.portalslist.filter));
});
$(document).on('click.portalslist', '#portalslist .filterAll', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,0));
});
$(document).on('click.portalslist', '#portalslist .filterRes', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,1));
});
$(document).on('click.portalslist', '#portalslist .filterEnl', function() {
$('#portalslist').html(window.plugin.portalslist.portalTable($(this).data('sort'),window.plugin.portalslist.sortOrder,2));
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -1,340 +1,15 @@
// ==UserScript==
// @id iitc-plugin-scoreboard@vita10gy
// @name IITC plugin: show a localized scoreboard.
// @category Info
// @category Deleted
// @version 0.1.9.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
// @description [@@BUILDNAME@@-@@BUILDDATE@@] A localized scoreboard.
// @description PLUGIN CURRENTLY UNAVAILABLE
// @include https://www.ingress.com/intel*
// @include http://www.ingress.com/intel*
// @match https://www.ingress.com/intel*
// @match http://www.ingress.com/intel*
// @grant none
// ==/UserScript==
@@PLUGINSTART@@
// PLUGIN START ////////////////////////////////////////////////////////
// use own namespace for plugin
window.plugin.scoreboard = function() {};
window.plugin.scoreboard.scores = {};
window.plugin.scoreboard.playerGuids = new Array();
window.plugin.scoreboard.resetTeam = function(team) {
var scores = window.plugin.scoreboard.scores['team'];
scores[team] = {};
scores[team]['mu'] = 0;
scores[team]['count_fields'] = 0;
scores[team]['count_links'] = 0;
scores[team]['count_portals'] = 0;
scores[team]['count_resonators'] = 0;
scores[team]['count_mods'] = 0;
scores[team]['link_length'] = 0;
scores[team]['field_area'] = 0;
scores[team]['largest'] = {};
};
window.plugin.scoreboard.initPlayer = function(player, team) {
var scores = window.plugin.scoreboard.scores['player'];
if(scores[player] === undefined) {
scores[player] = {};
scores[player]['team'] = team;
scores[player]['mu'] = 0;
scores[player]['count_fields'] = 0;
scores[player]['count_links'] = 0;
scores[player]['count_portals'] = 0;
scores[player]['count_resonators'] = 0;
scores[player]['link_length'] = 0;
scores[player]['field_area'] = 0;
scores[player]['count_mods'] = 0;
scores[player]['largest'] = {};
window.plugin.scoreboard.playerGuids.push(player);
}
}
window.plugin.scoreboard.compileStats = function() {
var somethingInView = false;
window.plugin.scoreboard.playerGuids = new Array();
window.plugin.scoreboard.scores = {'team': {}, 'player': {}};
var scores = window.plugin.scoreboard.scores;
window.plugin.scoreboard.resetTeam(TEAM_RES);
window.plugin.scoreboard.resetTeam(TEAM_ENL);
$.each(window.fields, function(qk, val) {
var team = getTeam(val.options.data);
// Google sends fields long since dead in the data. This makes sure it's still actually up.
if(window.portals[val.options.vertices.vertexA.guid] !== undefined ||
window.portals[val.options.vertices.vertexB.guid] !== undefined ||
window.portals[val.options.vertices.vertexC.guid] !== undefined ) {
var fieldArea = window.plugin.scoreboard.fieldArea(val);
somethingInView = true;
scores['team'][team]['count_fields']++;
scores['team'][team]['field_area'] += fieldArea;
val.options.data.fieldArea = fieldArea;
var largestArea = scores['team'][team]['largest']['field_area'];
if(largestArea === undefined || largestArea.options.data.fieldArea < val.options.data.fieldArea) {
largestArea = val;
}
scores['team'][team]['largest']['field_area'] = largestArea;
}
});
$.each(window.links, function(qk, link) {
somethingInView = true;
var team = getTeam(link.options.data);
scores['team'][team]['count_links']++;
var linkLength = window.plugin.scoreboard.portalDistance(link.options.data.edge.destinationPortalLocation,link.options.data.edge.originPortalLocation);
scores['team'][team]['link_length'] += linkLength;
var largestLink = scores['team'][team]['largest']['link'];
if(largestLink === undefined || largestLink.distance < linkLength) {
largestLink = {};
largestLink.distance = linkLength;
}
scores['team'][team]['largest']['link'] = largestLink;
});
$.each(window.portals, function(qk, portal) {
somethingInView = true;
var team = getTeam(portal.options.details);
if(team !== TEAM_NONE) {
var player = portal.options.details.captured.capturingPlayerId;
window.plugin.scoreboard.initPlayer(player, team);
scores['team'][team]['count_portals']++;
scores['player'][player]['count_portals']++;
$.each(portal.options.details.portalV2.linkedModArray, function(ind, mod) {
if(mod !== null) {
window.plugin.scoreboard.initPlayer(mod.installingUser, team);
somethingInView = true;
scores['team'][team]['count_mods']++;
scores['player'][mod.installingUser]['count_mods']++;
}
});
$.each(portal.options.details.resonatorArray.resonators, function(ind, reso) {
if(reso !== null) {
somethingInView = true;
window.plugin.scoreboard.initPlayer(reso.ownerGuid, team);
scores['team'][team]['count_resonators']++;
scores['player'][reso.ownerGuid]['count_resonators']++;
}
});
}
});
return somethingInView;
};
window.plugin.scoreboard.teamTableRow = function(field,title) {
var scores = window.plugin.scoreboard.scores['team'];
var retVal = '<tr><td>'
+ title
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_RES][field]))
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_ENL][field]))
+ '</td><td class="number">'
+ window.digits(Math.round(scores[TEAM_RES][field] + scores[TEAM_ENL][field]))
+ '</td></tr>';
return retVal;
};
window.plugin.scoreboard.fieldInfoArea = function(field) {
var title = '';
var retVal = '';
if(field !== undefined) {
var portal = window.portals[field.options.vertices.vertexA.guid];
if(portal !== undefined) {
title = ' @' + portal.options.details.portalV2.descriptiveText.TITLE;
}
retVal = '<div title="' + title + '">'
+ window.digits(Math.round(field.options.data.fieldArea))
+ '</div>';
} else {
retVal = 'N/A';
}
return retVal;
};
window.plugin.scoreboard.playerTableRow = function(playerGuid) {
var scores = window.plugin.scoreboard.scores['player'];
var retVal = '<tr class="'
+ (scores[playerGuid]['team'] === TEAM_RES ? 'res' : 'enl')
+'"><td>'
+ window.getPlayerName(playerGuid);
+ '</td>';
$.each(['count_portals','count_resonators','count_mods'], function(i, field) {
retVal += '<td class="number">'
+ window.digits(Math.round(scores[playerGuid][field]))
+ '</td>';
});
retVal += '</tr>';
return retVal;
};
window.plugin.scoreboard.playerTable = function(sortBy) {
// Sort the playerGuid array by sortBy
window.plugin.scoreboard.playerGuids.sort(function(a, b) {
var playerA = window.plugin.scoreboard.scores['player'][a];
var playerB = window.plugin.scoreboard.scores['player'][b];
var retVal = 0;
if(sortBy === 'names') {
retVal = window.getPlayerName(a).toLowerCase() < window.getPlayerName(b).toLowerCase() ? -1 : 1;
} else {
retVal = playerB[sortBy] - playerA[sortBy];
}
return retVal;
});
var sort = window.plugin.scoreboard.playerTableSort;
var scoreHtml = '<table>'
+ '<tr><th ' + sort('names', sortBy) + '>Player</th>'
+ '<th ' + sort('count_portals', sortBy) + '>Portals</th>'
+ '<th ' + sort('count_resonators', sortBy) + '>Resonators</th>'
+ '<th ' + sort('count_mods', sortBy) + '>Mods</th></tr>';
$.each(window.plugin.scoreboard.playerGuids, function(index, guid) {
scoreHtml += window.plugin.scoreboard.playerTableRow(guid);
});
scoreHtml += '</table>';
return scoreHtml;
}
// A little helper function so the above isn't so messy
window.plugin.scoreboard.playerTableSort = function(name, by) {
var retVal = 'data-sort="' + name + '"';
if(name === by) {
retVal += ' class="sorted"';
}
return retVal;
};
window.plugin.scoreboard.display = function() {
var somethingInView = window.plugin.scoreboard.compileStats();
var scores = window.plugin.scoreboard.scores;
var scoreHtml = '';
var title = '';
if(somethingInView) {
scoreHtml += '<table>'
+ '<tr><th></th><th class="number">Resistance</th><th class="number">Enlightened</th><th class="number">Total</th></tr>'
+ window.plugin.scoreboard.teamTableRow('count_fields','Field #')
+ window.plugin.scoreboard.teamTableRow('field_area','Field (km&sup2;)')
+ window.plugin.scoreboard.teamTableRow('count_links','Link #')
+ window.plugin.scoreboard.teamTableRow('link_length','Link (m)')
+ window.plugin.scoreboard.teamTableRow('count_portals','Portals')
+ window.plugin.scoreboard.teamTableRow('count_resonators','Resonators')
+ window.plugin.scoreboard.teamTableRow('count_mods','Mods')
+ '</table>';
scoreHtml += '<table>'
+ '<tr><th></th><th>Resistance</th><th>Enlightened</th></tr>'
+ '<tr><td>Largest Field (km&sup2;)</td><td>'
+ window.plugin.scoreboard.fieldInfoArea(scores['team'][TEAM_RES]['largest']['field_area'])
+ '</td><td>'
+ window.plugin.scoreboard.fieldInfoArea(scores['team'][TEAM_ENL]['largest']['field_area'])
+ '</td></tr>'
+ '<tr><td>Longest Link (m)</td><td>';
if(scores['team'][TEAM_RES]['largest']['link'] === undefined) {
scoreHtml += 'N/A';
}
else {
scoreHtml += window.digits(Math.round(scores['team'][TEAM_RES]['largest']['link']['distance']));
}
scoreHtml += '</td><td>';
if(scores['team'][TEAM_ENL]['largest']['link'] === undefined) {
scoreHtml += 'N/A';
}
else {
scoreHtml += window.digits(Math.round(scores['team'][TEAM_ENL]['largest']['link']['distance']));
}
scoreHtml += '</td></tr>'
+ '</table>'
+ '<div id="players">'
+ window.plugin.scoreboard.playerTable('count_portals')
+ '</div>';
scoreHtml += '<div class="disclaimer">Click on player table headers to sort by that column. '
+ 'Score is subject to portals available based on zoom level. '
+ 'If names are unresolved try again. For best results wait until updates are fully loaded.</div>';
} else {
scoreHtml += 'You need something in view.';
title = 'nothing in view';
}
dialog({
html: '<div id="scoreboard">' + scoreHtml + '</div>',
title: 'Scoreboard: ' + title,
dialogClass: 'ui-dialog-scoreboard',
id: 'scoreboard'
});
//run the name resolving process
resolvePlayerNames();
}
window.plugin.scoreboard.portalDistance = function(portalAE6Location, portalBE6Location) {
portalA = new L.LatLng(portalAE6Location.latE6 / 1E6, portalAE6Location.lngE6 / 1E6);
portalB = new L.LatLng(portalBE6Location.latE6 / 1E6, portalBE6Location.lngE6 / 1E6);
return (portalA.distanceTo(portalB));
}
window.plugin.scoreboard.fieldArea = function(field) {
var verts = field.options.vertices;
var sideA = window.plugin.scoreboard.portalDistance(verts.vertexA.location,verts.vertexB.location) / 1000;
var sideB = window.plugin.scoreboard.portalDistance(verts.vertexB.location,verts.vertexC.location) / 1000;
var sideC = window.plugin.scoreboard.portalDistance(verts.vertexC.location,verts.vertexA.location) / 1000;
// Heron's Formula;
var perimeter = sideA + sideB + sideC;
var s = perimeter/2;
return Math.sqrt(s*(s-sideA)*(s-sideB)*(s-sideC));
}
var setup = function() {
$('#toolbox').append(' <a onclick="window.plugin.scoreboard.display()" title="Display a scoreboard per team for the current view">Scoreboard</a>');
$('head').append('<style>' +
'.ui-dialog-scoreboard {width: auto !important; min-width: 400px !important; max-width: 600px !important;}' +
'#scoreboard table {margin-top:10px; border-collapse: collapse; empty-cells: show; width:100%; clear: both;}' +
'#scoreboard table td, #scoreboard table th {border-bottom: 1px solid #0b314e; padding:3px; color:white; background-color:#1b415e}' +
'#scoreboard table tr.res td { background-color: #005684; }' +
'#scoreboard table tr.enl td { background-color: #017f01; }' +
'#scoreboard table tr:nth-child(even) td { opacity: .8 }' +
'#scoreboard table tr:nth-child(odd) td { color: #ddd !important; }' +
'#scoreboard table th { text-align:left }' +
'#scoreboard table td.number, #scoreboard table th.number { text-align:right }' +
'#players table th { cursor:pointer; text-align: right;}' +
'#players table th:nth-child(1) { text-align: left;}' +
'#scoreboard table th.sorted { color:#FFCE00; }' +
'#scoreboard .disclaimer { margin-top:10px; font-size:10px; }' +
'.mu_score { margin-bottom: 10px; }' +
'.mu_score span { overflow: hidden; padding-top:2px; padding-bottom: 2px; display: block; font-weight: bold; float: left; box-sizing: border-box; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; }' +
'.mu_score span.res { background-color: #005684; text-align: right; padding-right:4px; }' +
'.mu_score span.enl { background-color: #017f01; padding-left: 4px; }' +
'</style>');
// Setup sorting
$(document).on('click', '#players table th', function() {
$('#players').html(window.plugin.scoreboard.playerTable($(this).data('sort')));
});
}
// PLUGIN END //////////////////////////////////////////////////////////
@@PLUGINEND@@

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-show-linked-portals@fstopienski
// @name IITC plugin: Show linked portals
// @category Portal Info
// @version 0.1.0.@@DATETIMEVERSION@@
// @version 0.1.1.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -35,6 +35,7 @@ window.plugin.showLinkedPortal.handleUpdate = function () {
}
window.plugin.showLinkedPortal.portalDetail = function (data) {
// don't render linked portal data if portal is neutral.
// (the data can remain sometimes - when a portal decays?)
if (data.portalDetails.controllingTeam.team == 'NEUTRAL')
@ -51,20 +52,17 @@ window.plugin.showLinkedPortal.portalDetail = function (data) {
$('.showLinkedPortalLink:not(.outOfRange)').bind('click', function () {
var guid = $(this).attr('data-guid');
if (window.portals[guid] !== undefined) {
window.selectPortal($(this).attr('data-guid'));
window.renderPortalDetails(window.selectedPortal);
var portalDetails = window.portals[guid].options.details;
var lat0 = portalDetails.locationE6.latE6 / 1E6;
var lon0 = portalDetails.locationE6.lngE6 / 1E6;
var Rlatlng = [lat0, lon0];
map.setView(Rlatlng, map.getZoom());
}
else {
// TODO: instead of just zooming out one level, check the link data for the start+end coordinates,
// and fit the map view to the bounding box
map.setZoom((map.getZoom() - 1));
window.renderPortalDetails(guid);
var latlng = findPortalLatLng(guid);
if (latlng) {
if (!map.getBounds().pad(-0.1).contains(latlng)) {
map.panTo(latlng);
}
} else {
// no idea where this portal is(!) - so step back one zoom level
map.setZoom(map.getZoom()-1);
}
});
}
@ -74,7 +72,7 @@ window.plugin.showLinkedPortal.getPortalByGuid = function (guid,isorigin) {
var portalInfoString;
if (window.portals[guid] !== undefined) {
var portalDetails = window.portals[guid].options.details;
var portalData = window.portals[guid].options.data;
var portalNameAddressAlt = "'" + portalDetails.portalV2.descriptiveText.TITLE + "' (" + portalDetails.portalV2.descriptiveText.ADDRESS + ")";
var portalNameAddressTitle = $('<div/>').append($('<strong/>').text(portalDetails.portalV2.descriptiveText.TITLE))
@ -90,7 +88,7 @@ window.plugin.showLinkedPortal.getPortalByGuid = function (guid,isorigin) {
.attr('title', portalNameAddressTitle))
.html();
} else {
var title = $('<div/>').append($('<strong/>').text('Zoom out'))
var title = $('<div/>').append($('<strong/>').text('Go to portal'))
.append($('<br/>'))
.append(linkDirection)
.html();

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-show-portal-weakness@vita10gy
// @name IITC plugin: show portal weakness
// @category Highlighter
// @version 0.7.1.@@DATETIMEVERSION@@
// @version 0.7.2.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -22,66 +22,28 @@
window.plugin.portalWeakness = function() {};
window.plugin.portalWeakness.highlightWeakness = function(data) {
var d = data.portal.options.details;
var portal_weakness = 0;
if(getTeam(d) !== 0) {
var only_mods = true;
var missing_mods = 0;
if(window.getTotalPortalEnergy(d) > 0 && window.getCurrentPortalEnergy(d) < window.getTotalPortalEnergy(d)) {
portal_weakness = 1 - (window.getCurrentPortalEnergy(d)/window.getTotalPortalEnergy(d));
only_mods = false;
}
//Ding the portal for every unapplicable mod.
$.each(d.portalV2.linkedModArray, function(ind, mod) {
if(mod === null || mod.type == 'MULTIHACK' || mod.type == 'HEATSINK' || mod.type == 'LINK_AMPLIFIER') {
if(mod === null) {
missing_mods++;
}
portal_weakness += .08;
}
});
//Ding the portal for every missing resonator.
var resCount = 0;
$.each(d.resonatorArray.resonators, function(ind, reso) {
if(reso === null) {
portal_weakness += .125;
only_mods = false;
} else {
resCount++;
}
});
if(portal_weakness < 0) {
portal_weakness = 0;
}
if(portal_weakness > 1) {
portal_weakness = 1;
}
if(portal_weakness > 0) {
var fill_opacity = portal_weakness*.85 + .15;
var color = 'orange';
if(only_mods) {
color = 'yellow';
//If only mods are missing, make portal yellow
// but fill more than usual since pale yellow is basically invisible
fill_opacity = missing_mods*.15 + .1;
} else if(missing_mods > 0) {
color = 'red';
}
fill_opacity = Math.round(fill_opacity*100)/100;
if(data.portal.options.team != TEAM_NONE) {
var res_count = data.portal.options.data.resCount;
var portal_health = data.portal.options.data.health;
var strength = (res_count/8) * (portal_health/100);
if(strength < 1) {
var fill_opacity = (1-strength)*.85 + .15;
var color = 'red';
var params = {fillColor: color, fillOpacity: fill_opacity};
if(resCount < 8) {
// Hole per missing resonator
var dash = new Array(8-resCount + 1).join("1,4,") + "100,0"
params["dashArray"] = dash;
// Hole per missing resonator
if (res_count < 8) {
var dash = new Array((8 - res_count) + 1).join("1,4,") + "100,0"
params.dashArray = dash;
}
data.portal.setStyle(params);
} else {
data.portal.setStyle({fillColor: COLORS[getTeam(data.portal.options.details)],
fillOpacity: 0.5,
dashArray: null});
}
}
}
}
var setup = function() {

View File

@ -2,7 +2,7 @@
// @id iitc-plugin-zaprange@zaso
// @name IITC plugin: Zaprange
// @category Layer
// @version 0.1.2.@@DATETIMEVERSION@@
// @version 0.1.3.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@
@ -25,11 +25,11 @@
window.plugin.zaprange.portalAdded = function(data) {
data.portal.on('add', function() {
window.plugin.zaprange.draw(this.options.guid, this.options.details.controllingTeam.team);
window.plugin.zaprange.draw(this.options.guid, this.options.data.team);
});
data.portal.on('remove', function() {
window.plugin.zaprange.remove(this.options.guid, this.options.details.controllingTeam.team);
window.plugin.zaprange.remove(this.options.guid, this.options.data.team);
});
}
@ -51,7 +51,7 @@
if(faction !== "NEUTRAL") {
var coo = d._latlng;
var latlng = new L.LatLng(coo.lat,coo.lng);
var portalLevel = parseInt(getPortalLevel(d.options.details));
var portalLevel = d.options.level;
var optCircle = {color:'red',opacity:0.7,fillColor:'red',fillOpacity:0.1,weight:1,clickable:false, dashArray: [10,6]};
var range = (5*portalLevel)+35;