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

View File

@ -171,7 +171,7 @@ window.artifact.updateLayer = function() {
artifact._layer.clearLayers();
$.each(artifact.portalInfo, function(guid,data) {
var latlng = L.latLng ([data._entityData.locationE6.latE6/1E6, data._entityData.locationE6.lngE6/1E6]);
var latlng = L.latLng ([data._entityData.latE6/1E6, data._entityData.lngE6/1E6]);
// jarvis shard icon
var iconUrl = undefined;
@ -235,8 +235,8 @@ window.artifact.showArtifactList = function() {
var sortVal = 0;
var onclick = 'zoomToAndShowPortal(\''+guid+'\',['+data._entityData.locationE6.latE6/1E6+','+data._entityData.locationE6.lngE6/1E6+'])';
var row = '<tr><td class="portal"><a onclick="'+onclick+'" title="'+escapeHtmlSpecialChars(data._entityData.portalV2.descriptiveText.ADDRESS||'')+'">'+escapeHtmlSpecialChars(data._entityData.portalV2.descriptiveText.TITLE)+'</a></td>';
var onclick = 'zoomToAndShowPortal(\''+guid+'\',['+data._entityData.latE6/1E6+','+data._entityData.lngE6/1E6+'])';
var row = '<tr><td class="portal"><a onclick="'+onclick+'">'+escapeHtmlSpecialChars(data._entityData.title)+'</a></td>';
row += '<td class="info">';

View File

@ -338,7 +338,6 @@ window.setMapBaseLayer = function() {
// included as inline script in the original site, the data is static
// and cannot be updated.
window.setupPlayerStat = function() {
PLAYER.guid = playerNameToGuid(PLAYER.nickname);
var level;
var ap = parseInt(PLAYER.ap);
for(level = 0; level < MIN_AP_FOR_LEVEL.length; level++) {
@ -531,7 +530,6 @@ function boot() {
window.setupTaphold();
window.setupStyles();
window.setupDialogs();
window.setupPlayerNameCache();
window.setupMap();
window.setupGeosearch();
window.setupRedeem();
@ -542,6 +540,7 @@ function boot() {
window.setupPlayerStat();
window.setupTooltips();
window.chat.setup();
window.portalDetail.setup();
window.setupQRLoadLib();
window.setupLayerChooserSelectOne();
window.setupLayerChooserStatusRecorder();

View File

@ -127,7 +127,7 @@ window.chat.requestFaction = function(getOlderMsgs, isRetry) {
var d = chat.genPostData(true, chat._faction, getOlderMsgs);
var r = window.postAjax(
'getPaginatedPlextsV2',
'getPaginatedPlexts',
d,
function(data, textStatus, jqXHR) { chat.handleFaction(data, getOlderMsgs); },
isRetry
@ -178,7 +178,7 @@ window.chat.requestPublic = function(getOlderMsgs, isRetry) {
var d = chat.genPostData(false, chat._public, getOlderMsgs);
var r = window.postAjax(
'getPaginatedPlextsV2',
'getPaginatedPlexts',
d,
function(data, textStatus, jqXHR) { chat.handlePublic(data, getOlderMsgs); },
isRetry
@ -284,11 +284,9 @@ window.chat.writeDataToHash = function(newData, storageHash, isPublicChannel, is
switch(markup[0]) {
case 'SENDER': // user generated messages
nick = markup[1].plain.slice(0, -2); // cut “: ” at end
pguid = markup[1].guid;
break;
case 'PLAYER': // automatically generated messages
pguid = markup[1].guid;
nick = markup[1].plain;
team = markup[1].team === 'RESISTANCE' ? TEAM_RES : TEAM_ENL;
if(ind > 0) msg += nick; // dont repeat nick directly
@ -351,13 +349,9 @@ window.chat.writeDataToHash = function(newData, storageHash, isPublicChannel, is
if ((!isPublicChannel) && (!isSecureMessage)) msg = '<span style="color: #ff6">[public]</span> ' + msg;
// format: timestamp, autogenerated, HTML message, player guid
storageHash.data[json[0]] = [json[1], auto, chat.renderMsg(msg, nick, time, team, msgToPlayer, systemNarrowcast), pguid];
// format: timestamp, autogenerated, HTML message
storageHash.data[json[0]] = [json[1], auto, chat.renderMsg(msg, nick, time, team, msgToPlayer, systemNarrowcast)];
// if we're processing older messages, we could be looking at pre-name change mentions or similar
// so in that case, flag it so we don't overwrite existing name cache entries.
// (it's not perfect - the initial request has the wrong value here)
window.setPlayerName(pguid, nick, isOlderMsgs); // free nick name resolves.
});
}

View File

@ -8,8 +8,14 @@
// given the entity detail data, returns the team the entity belongs
// to. Uses TEAM_* enum values.
window.getTeam = function(details) {
return teamStringToId(details.controllingTeam.team);
}
window.teamStringToId = function(teamStr) {
var team = TEAM_NONE;
if(details.controllingTeam.team === 'ALIENS' || details.controllingTeam.team === 'ENLIGHTENED') team = TEAM_ENL;
if(details.controllingTeam.team === 'RESISTANCE') team = TEAM_RES;
if(teamStr === 'ENLIGHTENED') team = TEAM_ENL;
if(teamStr === 'RESISTANCE') team = TEAM_RES;
return team;
}

View File

@ -48,7 +48,8 @@
// called after each map data request finished. Argument is
// {success: boolean} indicated the request success or fail.
// iitcLoaded: called after IITC and all plugins loaded
// portalDetailLoaded: called when a request to load full portal detail
// completes. guid, success, details parameters
window._hooks = {}
window.VALID_HOOKS = [
@ -58,7 +59,8 @@ window.VALID_HOOKS = [
'portalDetailsUpdated',
'publicChatDataAvailable', 'factionChatDataAvailable',
'requestFinished', 'nicknameClicked',
'geoSearch', 'iitcLoaded'];
'geoSearch', 'iitcLoaded',
'portalDetailLoaded'];
window.runHooks = function(event, data) {
if(VALID_HOOKS.indexOf(event) === -1) throw('Unknown event type: ' + event);

View File

@ -104,7 +104,6 @@ window.Render.prototype.processDeletedGameEntityGuids = function(deleted) {
}
window.Render.prototype.processGameEntities = function(entities) {
var portalGuids = [];
for (var i in entities) {
var ent = entities[i];
@ -112,14 +111,9 @@ window.Render.prototype.processGameEntities = function(entities) {
// don't create entities in the 'deleted' list
if (!(ent[0] in this.deletedGuid)) {
this.createEntity(ent);
if ('portalV2' in ent[2]) portalGuids.push(ent[0]);
}
}
// now reconstruct links 'optimised' out of the data from the portal link data
for (var i in portalGuids) {
this.createLinksFromPortalData(portalGuids[i]);
}
}
@ -130,6 +124,7 @@ window.Render.prototype.endRenderPass = function() {
// check to see if there are any entities we haven't seen. if so, delete them
for (var guid in window.portals) {
// special case for selected portal - it's kept even if not seen
// artifact (e.g. jarvis shard) portals are also kept - but they're always 'seen'
if (!(guid in this.seenPortalsGuid) && guid !== selectedPortal) {
this.deletePortalEntity(guid);
}
@ -214,22 +209,6 @@ window.Render.prototype.deleteFieldEntity = function(guid) {
var f = window.fields[guid];
var fd = f.options.details;
var deletePortalLinkedField = function(pguid) {
if (pguid in window.portals) {
var pd = window.portals[pguid].options.details;
if (pd.portalV2.linkedFields) {
var i = pd.portalV2.linkedFields.indexOf(guid);
if (i >= 0) {
pd.portalV2.linkedFields.splice(i,1);
}
}
}
}
deletePortalLinkedField (fd.capturedRegion.vertexA.guid);
deletePortalLinkedField (fd.capturedRegion.vertexB.guid);
deletePortalLinkedField (fd.capturedRegion.vertexC.guid);
fieldsFactionLayers[f.options.team].removeLayer(f);
delete window.fields[guid];
}
@ -244,23 +223,30 @@ window.Render.prototype.createEntity = function(ent) {
// logic on detecting entity type based on the stock site javascript.
if ("portalV2" in ent[2]) {
this.createPortalEntity(ent);
} else if ("capturedRegion" in ent[2]) {
this.createFieldEntity(ent);
} else if ("edge" in ent[2]) {
this.createLinkEntity(ent);
} else {
console.warn("Unknown entity found: "+JSON.stringify(ent));
}
switch (ent[2].type) {
case 'portal':
this.createPortalEntity(ent);
break;
case 'edge':
this.createLinkEntity(ent);
break;
case 'region':
this.createFieldEntity(ent);
break;
default:
console.warn('unknown entity found: '+JSON.stringify(ent));
break;
}
}
window.Render.prototype.createPortalEntity = function(ent) {
this.seenPortalsGuid[ent[0]] = true; // flag we've seen it
var previousDetails = undefined;
var previousData = undefined;
// check if entity already exists
if (ent[0] in window.portals) {
@ -275,21 +261,17 @@ window.Render.prototype.createPortalEntity = function(ent) {
// remember the old details, for the callback
previousDetails = p.options.details;
previousData = p.options.data;
this.deletePortalEntity(ent[0]);
}
var portalLevel = getPortalLevel(ent[2]);
var team = getTeam(ent[2]);
var portalLevel = parseInt(ent[2].level);
var team = teamStringToId(ent[2].team);
// the data returns unclaimed portals as level 1 - but IITC wants them treated as level 0
if (team == TEAM_NONE) portalLevel = 0;
var latlng = L.latLng(ent[2].locationE6.latE6/1E6, ent[2].locationE6.lngE6/1E6);
//TODO: move marker creation, style setting, etc into a separate class
//(as it's called from elsewhere - e.g. selecting/deselecting portals)
//ALSO: change API for highlighters - make them return the updated style rather than directly calling setStyle on the portal marker
//(can this be done in a backwardly-compatible way??)
var latlng = L.latLng(ent[2].latE6/1E6, ent[2].lngE6/1E6);
var dataOptions = {
level: portalLevel,
@ -297,32 +279,16 @@ window.Render.prototype.createPortalEntity = function(ent) {
ent: ent, // LEGACY - TO BE REMOVED AT SOME POINT! use .guid, .timestamp and .details instead
guid: ent[0],
timestamp: ent[1],
details: ent[2]
data: ent[2]
};
// Javascript uses references for objects. For now, at least, we need to modify the data within
// the options.details.portalV2 (to add in linkedFields). To avoid tainting the original data (which may be cached)
// we'll shallow-copy these items
dataOptions.details = $.extend({}, dataOptions.details);
dataOptions.details.portalV2 = $.extend({}, dataOptions.details.portalV2);
// create a linkedFields entry and add it to details - various bits of code assumes it will exist
for (var fguid in window.fields) {
var fd = window.fields[fguid].options.details;
if ( fd.capturedRegion.vertexA.guid == ent[0] || fd.capturedRegion.vertexB.guid == ent[0] || fd.capturedRegion.vertexC.guid == ent[0]) {
if (!dataOptions.details.portalV2.linkedFields) dataOptions.details.portalV2.linkedFields = [];
dataOptions.details.portalV2.linkedFields.push(fguid);
}
}
var marker = createMarker(latlng, dataOptions);
marker.on('click', function() { window.renderPortalDetails(ent[0]); });
marker.on('dblclick', function() { window.renderPortalDetails(ent[0]); window.map.setView(latlng, 17); });
window.runHooks('portalAdded', {portal: marker, previousDetails: previousDetails});
window.runHooks('portalAdded', {portal: marker, previousData: previousData});
window.portals[ent[0]] = marker;
@ -370,12 +336,11 @@ window.Render.prototype.createFieldEntity = function(ent) {
this.deleteFieldEntity(ent[0]); // option 2, for now
}
var team = getTeam(ent[2]);
var reg = ent[2].capturedRegion;
var team = teamStringToId(ent[2].team);
var latlngs = [
L.latLng(reg.vertexA.location.latE6/1E6, reg.vertexA.location.lngE6/1E6),
L.latLng(reg.vertexB.location.latE6/1E6, reg.vertexB.location.lngE6/1E6),
L.latLng(reg.vertexC.location.latE6/1E6, reg.vertexC.location.lngE6/1E6)
L.latLng(ent[2].points[0].latE6/1E6, ent[2].points[0].lngE6/1E6),
L.latLng(ent[2].points[1].latE6/1E6, ent[2].points[1].lngE6/1E6),
L.latLng(ent[2].points[2].latE6/1E6, ent[2].points[2].lngE6/1E6)
];
var poly = L.geodesicPolygon(latlngs, {
@ -387,27 +352,9 @@ window.Render.prototype.createFieldEntity = function(ent) {
team: team,
guid: ent[0],
timestamp: ent[1],
details: ent[2],
// LEGACY FIELDS: these duplicate data available via .details, as IITC previously stored it in data and vertices
data: ent[2],
vertices: ent[2].capturedRegion
});
// now fill in any references portals linkedFields data
var addPortalLinkedField = function(pguid) {
if (pguid in window.portals) {
var pd = window.portals[pguid].options.details;
if (!pd.portalV2.linkedFields) pd.portalV2.linkedFields = [];
if (pd.portalV2.linkedFields.indexOf(pguid) <0 ) {
pd.portalV2.linkedFields.push (ent[0]);
}
}
}
addPortalLinkedField(ent[2].capturedRegion.vertexA.guid);
addPortalLinkedField(ent[2].capturedRegion.vertexB.guid);
addPortalLinkedField(ent[2].capturedRegion.vertexC.guid);
runHooks('fieldAdded',{field: poly});
window.fields[ent[0]] = poly;
@ -433,11 +380,10 @@ window.Render.prototype.createLinkEntity = function(ent,faked) {
this.deleteLinkEntity(ent[0]); // option 2 - for now
}
var team = getTeam(ent[2]);
var edge = ent[2].edge;
var team = teamStringToId(ent[2].team);
var latlngs = [
L.latLng(edge.originPortalLocation.latE6/1E6, edge.originPortalLocation.lngE6/1E6),
L.latLng(edge.destinationPortalLocation.latE6/1E6, edge.destinationPortalLocation.lngE6/1E6)
L.latLng(ent[2].oLatE6/1E6, ent[2].oLngE6/1E6),
L.latLng(ent[2].dLatE6/1E6, ent[2].dLngE6/1E6)
];
var poly = L.geodesicPolyline(latlngs, {
color: COLORS[team],
@ -448,8 +394,6 @@ window.Render.prototype.createLinkEntity = function(ent,faked) {
team: team,
guid: ent[0],
timestamp: ent[1],
details: ent[2],
// LEGACY FIELDS: these duplicate data available via .details, as IITC previously stored it in data and vertices
data: ent[2]
});
@ -465,56 +409,6 @@ window.Render.prototype.createLinkEntity = function(ent,faked) {
}
window.Render.prototype.createLinksFromPortalData = function(portalGuid) {
var sourcePortal = portals[portalGuid];
for (var sourceLinkIndex in sourcePortal.options.details.portalV2.linkedEdges||[]) {
var sourcePortalLinkInfo = sourcePortal.options.details.portalV2.linkedEdges[sourceLinkIndex];
// portals often contain details for edges that don't exist. so only consider faking an edge if this
// is the origin portal
if (sourcePortalLinkInfo.isOrigin) {
// ... and the other porta has matching link information.
if (sourcePortalLinkInfo.otherPortalGuid in portals) {
var targetPortal = portals[sourcePortalLinkInfo.otherPortalGuid];
for (var targetLinkIndex in targetPortal.options.details.portalV2.linkedEdges||[]) {
var targetPortalLinkInfo = targetPortal.options.details.portalV2.linkedEdges[targetLinkIndex];
if (targetPortalLinkInfo.edgeGuid == sourcePortalLinkInfo.edgeGuid) {
// yes - edge in both portals. create it
var fakeEnt = [
sourcePortalLinkInfo.edgeGuid,
0, // mtime for entity data - unknown when faking it, so zero will be the oldest possible
{
controllingTeam: sourcePortal.options.details.controllingTeam,
edge: {
originPortalGuid: portalGuid,
originPortalLocation: sourcePortal.options.details.locationE6,
destinationPortalGuid: sourcePortalLinkInfo.otherPortalGuid,
destinationPortalLocation: targetPortal.options.details.locationE6
}
}
];
this.createLinkEntity(fakeEnt,true);
}
}
}
}
}
}
window.Render.prototype.updateEntityVisibility = function() {
if (this.entityVisibilityZoom === undefined || this.entityVisibilityZoom != map.getZoom()) {

View File

@ -28,7 +28,7 @@ window.MapDataRequest = function() {
this.MIN_TILES_PER_REQUEST = 4;
// number of times to retry a tile after a 'bad' error (i.e. not a timeout)
this.MAX_TILE_RETRIES = 3;
this.MAX_TILE_RETRIES = 1;
// refresh timers
this.MOVE_REFRESH = 1; //time, after a map move (pan/zoom) before starting the refresh processing
@ -45,7 +45,7 @@ window.MapDataRequest = function() {
this.RUN_QUEUE_DELAY = 0.5;
// delay before requeuing tiles in failed requests
this.BAD_REQUEST_REQUEUE_DELAY = 5; // longer delay before retrying a completely failed request - as in this case the servers are struggling
this.BAD_REQUEST_REQUEUE_DELAY = 10; // longer delay before retrying a completely failed request - as in this case the servers are struggling
// a delay before processing the queue after requeuing tiles. this gives a chance for other requests to finish
// or other requeue actions to happen before the queue is processed, allowing better grouping of requests
@ -391,7 +391,7 @@ window.MapDataRequest.prototype.sendTileRequest = function(tiles) {
var savedThis = this;
// NOTE: don't add the request with window.request.add, as we don't want the abort handling to apply to map data any more
window.postAjax('getThinnedEntitiesV4', data,
window.postAjax('getThinnedEntities', data,
function(data, textStatus, jqXHR) { savedThis.handleResponse (data, tiles, true); }, // request successful callback
function() { savedThis.handleResponse (undefined, tiles, false); } // request failed callback
);

View File

@ -14,140 +14,52 @@
var requestParameterMunges = [
// obsolete munge sets (they don't have some of the new parameters) deleted
// set 7 - 2013-11-06
// set 10 - 2013-11-27
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfuscated?!)
'dashboard.getGameScore': 'yol4dxx5ufqolhk2', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': '7b83j2z81rtk6101', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '46su4lrisoq28gxh', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'wsc5puahrymtf1qh', // LOOKUP_PLAYERS
'dashboard.redeemReward': 'oo0n7pw2m0xufpzx', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'bo1bp74rz8kbdjkb', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'q0f8o4v9t8pt91yv', // SEND_PLEXT
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO
'dashboard.getGameScore': '4oid643d9zc168hs', // GET_GAME_SCORE
'dashboard.getPaginatedPlexts': 's1msyywq51ntudpe', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntities': '4467ff9bgxxe4csa', // GET_THINNED_ENTITIES
'dashboard.getPortalDetails': 'c00thnhf1yp3z6mn', // GET_PORTAL_DETAILS
'dashboard.redeemReward': '66l9ivg39ygfqqjm', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'cgb7hi5hglv0xx8k', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'etn9xq7brd6947kq', // SEND_PLEXT
// common parameters
method: 'imo60cdzkemxduub',
version: '54lh4o0q7nz7dao9', //guessed parameter name - only seen munged
version_parameter: '370c0b4e160ed26c8c4ce40f10f546545730e1ef', // passed as the value to the above parameter
method: 'yyngyttbmmbuvdpa',
version: 'avz401t36lzrapis',
version_parameter: 'c5d0a5d608f729a1232bebdc12fb86ba5fb6c43f',
// GET_THINNED_ENTITIES
quadKeys: 'iqy8e2d3zpne0cmh', //guessed parameter name - only seen munged
quadKeys: '1mpmxz2yun22rwnn',
// GET_PAGINATED_PLEXTS
desiredNumItems: 'chwe3yko3xy0qlk3',
minLatE6: 'f31z3x27ua8i05cf',
minLngE6: 't0rmob7f42c0w04r',
maxLatE6: 'ebwfvri5io9q0tvu',
maxLngE6: 'lfqzvpj92dp8uxo6',
minTimestampMs: '23a6djyyieeaeduu',
maxTimestampMs: 'zhjtsm2gw7w3b7mx',
chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'v5rzzxtg5rmry3dx',
desiredNumItems: 'nzd23jqm9k1cnnij',
minLatE6: '0dod6onpa1s4fezp',
minLngE6: 'soass3t7mm7anneo',
maxLatE6: 'cvarmr3o00ngylo1',
maxLngE6: 'udzwnlx07hzd3bfo',
minTimestampMs: '9iiiks138gkf8xho',
maxTimestampMs: '94wm0u3sc3sgzq7x',
chatTab: 'tqfj4a3okzn5v5o1',
ascendingTimestampOrder: '5jv1m90sq35u6utq',
// SEND_PLEXT
message: 'onptntn3szan21lj',
latE6: '1jq9lgu3hjajrt7s',
lngE6: 'plbubiopnavbxxh6',
// chatTab: 'tak64gipm3hhqpnh', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '919p2cfpdo2wz03n',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'thpbnoyjx0antwm5',
},
// set 8 - 2013-11-07
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfuscated?!)
'dashboard.getGameScore': 'lls4clhel87apzpa', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': 'r6n2xgcd8wjsm4og', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '1ybigzcf2sifu34b', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': 'uig0xeb6trclqd2l', // LOOKUP_PLAYERS
'dashboard.redeemReward': '7dd7x64cc2lbutoq', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'd8p6dvwilsr460u3', // SEND_INVITE_EMAIL
'dashboard.sendPlext': 'repg2orpg7htkoto', // SEND_PLEXT
// common parameters
method: '97aes4vnlvyhoxik',
version: 'an8mglz21qabq3wq', //guessed parameter name - only seen munged
version_parameter: 'b92c9d055fcdf715887b173c706e7a2c267e32c5', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: 'mhjknavysslwfhk6', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: 'l61g8u397alq3j1x',
minLatE6: 'wwsvpboc5bxd1s9q',
minLngE6: '48l4x7ngfsz47z3u',
maxLatE6: 'p3m1qg81uqldizu6',
maxLngE6: 'h4kv1eef878vfyk3',
minTimestampMs: 'uj1vcy9ufws24v2c',
maxTimestampMs: '8pt1x5nd9hk5vakv',
chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'duyuskmky68nl2ci',
// SEND_PLEXT
message: 'xktwjguq0nohzioa',
latE6: 'm4crflfaibmg9mdf',
lngE6: 'h6jfungrw5ii830r',
// chatTab: 'zy1yc1rfczashshu', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: '3u9h9cpfh2yiy4fk',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'jpg3y4ax7t0w356j',
},
// set 9 - 2013-11-1
{
'dashboard.getArtifactInfo': 'artifacts', // GET_ARTIFACT_INFO: new (and not obfuscated?!)
'dashboard.getGameScore': '9w8phj2dccvns3t9', // GET_GAME_SCORE
'dashboard.getPaginatedPlextsV2': '3b1nc3ub0sd1704x', // GET_PAGINATED_PLEXTS
'dashboard.getThinnedEntitiesV4': '2xa55qj41qrhfhas', // GET_THINNED_ENTITIES
'dashboard.getPlayersByGuids': '734hxjh89d53clqq', // LOOKUP_PLAYERS
'dashboard.redeemReward': 'k3hwg41wf112gjjh', // REDEEM_REWARD
'dashboard.sendInviteEmail': 'uwizjeb18xmcesa0', // SEND_INVITE_EMAIL
'dashboard.sendPlext': '5au1m1hut1gyvnix', // SEND_PLEXT
// common parameters
method: '3sld77nsm0tjmkvi',
version: 'xz7q6r3aja5ttvoo', //guessed parameter name - only seen munged
version_parameter: 'b121024077de2a0dc6b34119e4440785c9ea5e64', // passed as the value to the above parameter
// GET_THINNED_ENTITIES
quadKeys: '0o6bkrbwevwn6bg1', //guessed parameter name - only seen munged
// GET_PAGINATED_PLEXTS
desiredNumItems: '3fketl1tv01q7vxu',
minLatE6: '5i6jhgbv3aq3c4qz',
minLngE6: 'pe2io3r932qysg4u',
maxLatE6: 'plzyuy89bnlb3pth',
maxLngE6: 'q0qq1ooc7sxpynth',
minTimestampMs: 'nc282s8hdklv21mw',
maxTimestampMs: 'ezrljj0l71gpelpu',
chatTab: 'efaznrayv5n3jxs0', //guessed parameter name - only seen munged
ascendingTimestampOrder: 'fcmlcb8ya0oa1clk',
// SEND_PLEXT
message: 'jg4ms2i14rgzi02n',
latE6: 'nkf3evzpkxkq8l2q',
lngE6: '7xoz0xl8se4d1j53',
message: '8exta9k7y8huhqmc',
latE6: 'kqek161gza3kjcry',
lngE6: '3dlxsqrjj2vcmhbc',
// chatTab: 'efaznrayv5n3jxs0', //guessed parameter name - only seen munged
// LOOKUP_PLAYERS
guids: 'm4dcrdltldigfo94',
// GET_PORTAL_DETAILS
guid: 'seg6ohxgnqf9xu9w',
// SEND_INVITE_EMAIL
inviteeEmailAddress: 'rye9be4um2t1z5ts',
inviteeEmailAddress: '8exta9k7y8huhqmc',
},
];
var activeRequestMungeSet = undefined;
// in the recent stock site updates, their javascript code has been less obfuscated, but also the munge parameters
// change on every release. I can only assume it's now an integrated step in the build/release system, rather
@ -158,14 +70,15 @@ function extractMungeFromStock() {
var foundMunges = {};
// these are easy - directly available in variables
foundMunges['dashboard.getArtifactInfo'] = nemesis.dashboard.requests.MethodName.GET_ARTIFACT_INFO;
foundMunges['dashboard.getGameScore'] = nemesis.dashboard.requests.MethodName.GET_GAME_SCORE;
foundMunges['dashboard.getPaginatedPlextsV2'] = nemesis.dashboard.requests.MethodName.GET_PAGINATED_PLEXTS;
foundMunges['dashboard.getThinnedEntitiesV4'] = nemesis.dashboard.requests.MethodName.GET_THINNED_ENTITIES;
foundMunges['dashboard.getPlayersByGuids'] = nemesis.dashboard.requests.MethodName.LOOKUP_PLAYERS;
foundMunges['dashboard.redeemReward'] = nemesis.dashboard.requests.MethodName.REDEEM_REWARD;
foundMunges['dashboard.sendInviteEmail'] = nemesis.dashboard.requests.MethodName.SEND_INVITE_EMAIL;
foundMunges['dashboard.sendPlext'] = nemesis.dashboard.requests.MethodName.SEND_PLEXT;
// NOTE: the .toString() is there so missing variables throw an exception, rather than storing 'undefined'
foundMunges['dashboard.getArtifactInfo'] = nemesis.dashboard.requests.MethodName.GET_ARTIFACT_INFO.toString();
foundMunges['dashboard.getGameScore'] = nemesis.dashboard.requests.MethodName.GET_GAME_SCORE.toString();
foundMunges['dashboard.getPaginatedPlexts'] = nemesis.dashboard.requests.MethodName.GET_PAGINATED_PLEXTS.toString();
foundMunges['dashboard.getThinnedEntities'] = nemesis.dashboard.requests.MethodName.GET_THINNED_ENTITIES.toString();
foundMunges['dashboard.getPortalDetails'] = nemesis.dashboard.requests.MethodName.GET_PORTAL_DETAILS.toString();
foundMunges['dashboard.redeemReward'] = nemesis.dashboard.requests.MethodName.REDEEM_REWARD.toString();
foundMunges['dashboard.sendInviteEmail'] = nemesis.dashboard.requests.MethodName.SEND_INVITE_EMAIL.toString();
foundMunges['dashboard.sendPlext'] = nemesis.dashboard.requests.MethodName.SEND_PLEXT.toString();
// the rest are trickier - we need to parse the functions of the stock site. these break very often
// on site updates
@ -218,11 +131,11 @@ function extractMungeFromStock() {
var chatTab = result[7] || result[8];
if (chatTab != foundMunges.chatTab) throw 'Error: inconsistent munge parsing for chatTab';
// LOOKUP_PLAYERS
var reg = new RegExp('LOOKUP_PLAYERS, {'+mungeRegExpLit+'a}');
var result = reg.exec(nemesis.dashboard.network.DataFetcher.prototype.lookupPlayersByGuids.toString());
// GET_PORTAL_DETAILS
var reg = new RegExp('GET_PORTAL_DETAILS, {'+mungeRegExpLit+'a}');
var result = reg.exec(nemesis.dashboard.network.DataFetcher.prototype.getPortalDetails.toString());
foundMunges.guids = result[1] || result[2];
foundMunges.guid = result[1] || result[2];
// SEND_INVITE_EMAIL
var reg = new RegExp('SEND_INVITE_EMAIL, {'+mungeRegExpLit+'b}');
@ -244,44 +157,32 @@ window.detectActiveMungeSet = function() {
// first, try and parse the stock functions and extract the munges directly
activeMunge = extractMungeFromStock();
if (activeMunge) {
console.log('IITC: Successfully extracted munges from stock javascript');
return;
}
// try and find the stock page functions
// FIXME? revert to searching through all the code? is that practical?
var stockFunc;
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.doSendRequest_.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.XhrController.prototype.sendRequest.toString();
} catch(e) {
try {
stockFunc = nemesis.dashboard.network.DataFetcher.prototype.sendRequest_.toString();
} catch(e) {
console.warn('Failed to find a relevant function in the stock site');
}
}
}
if(stockFunc) {
for (var i in requestParameterMunges) {
if (stockFunc.indexOf (requestParameterMunges[i]['method']) >= 0) {
console.log('IITC: found request munge set index '+i+' in stock intel site');
activeRequestMungeSet = i;
}
}
console.log('IITC: Successfully extracted munges from stock javascript - excellent work!');
} else {
console.error('IITC: failed to find the stock site function for detecting munge set');
console.warn('IITC: failed to detect a munge set from the code - searching our list...');
// try to find a matching munge set from the pre-defined ones. this code remains as in the case of
// things breaking it can be quicker to update the table than to fix the regular expressions used
// above
try {
for (var i in requestParameterMunges) {
if (requestParameterMunges[i]['dashboard.getThinnedEntities'] == nemesis.dashboard.requests.MethodName.GET_THINNED_ENTITIES) {
console.log('IITC: found a match with munge set index '+i);
activeMunge = requestParameterMunges[i];
break;
}
}
} catch(e) {
console.warn('IITC: failed to find matching munge set from supplied list');
}
}
if (activeRequestMungeSet===undefined) {
console.error('IITC: failed to find request munge set - IITC will likely fail');
activeRequestMungeSet = 0;
if (!activeMunge) {
console.warn('IITC: Error!! failed to find a parameter munge set - neither extracting from stock, or searching through table. IITC CANNOT WORK');
throw {error:'Failed to find a munge set'};
}
activeMunge = requestParameterMunges[activeRequestMungeSet];
}

View File

@ -1,152 +1,18 @@
// PLAYER NAMES //////////////////////////////////////////////////////
// Player names are cached in sessionStorage. There is no GUI
// element from within the total conversion to clean them, but you
// can run sessionStorage.clean() to reset it.
window.setupPlayerNameCache = function() {
// IITC used to store player names in localStorage rather than sessionStorage. lets clear out any cached
// names from session storage
var matchPlayerGuid = new RegExp ('^[0-9a-f]{32}\\.c$');
$.each(Object.keys(localStorage), function(ind,key) {
if ( matchPlayerGuid.test(key) ) {
// copy from localStorage to sessionStorage if not already there
if (!sessionStorage[key]) sessionStorage[key] = localStorage[key];
// then clear from localStorage
localStorage.removeItem(key);
}
});
}
// retrieves player name by GUID. If the name is not yet available, it
// will be added to a global list of GUIDs that need to be resolved.
// The resolve method is not called automatically.
window.getPlayerName = function(guid) {
if(sessionStorage[guid]) return sessionStorage[guid];
// only add to queue if it isnt already
if(playersToResolve.indexOf(guid) === -1 && playersInResolving.indexOf(guid) === -1) {
playersToResolve.push(guid);
}
return '{'+guid.slice(0, 12)+'}';
}
window._playerNameToGuidCache = {};
window.playerNameToGuid = function(playerName) {
var cachedGuid = window._playerNameToGuidCache[playerName];
if (cachedGuid !== undefined) return cachedGuid;
// IITC needs our own player GUID, from a lookup by name. so we retrieve this from localstorage (if available)
if (playerName == PLAYER.nickname) {
cachedGuid = localStorage['PLAYER-'+PLAYER.nickname];
if (cachedGuid !== undefined) return cachedGuid;
}
var guid = null;
$.each(Object.keys(sessionStorage), function(ind,key) {
if(playerName === sessionStorage[key]) {
guid = key;
window._playerNameToGuidCache[playerName] = guid;
return false; //break from $.each
}
});
return guid;
}
// resolves all player GUIDs that have been added to the list. Reruns
// renderPortalDetails when finished, so that then-unresolved names
// get replaced by their correct versions.
window.resolvePlayerNames = function() {
if(window.playersToResolve.length === 0) return;
//limit per request. stock site is never more than 13 (8 res, 4 mods, owner)
//testing shows 15 works and 20 fails
var MAX_RESOLVE_PLAYERS_PER_REQUEST = 15;
var MAX_RESOLVE_REQUESTS = 8;
if (window.playersToResolve.length > MAX_RESOLVE_PLAYERS_PER_REQUEST*MAX_RESOLVE_REQUESTS) {
console.log('Warning: player name resolve queue had '+window.playersToResolve.length+' entries. Limiting to the first '+MAX_RESOLVE_PLAYERS_PER_REQUEST*MAX_RESOLVE_REQUESTS+' to prevent excessive requests');
window.playersToResolve = playersToResolve.slice(0,MAX_RESOLVE_PLAYERS_PER_REQUEST*MAX_RESOLVE_REQUESTS);
}
var p = window.playersToResolve.slice(0,MAX_RESOLVE_PLAYERS_PER_REQUEST);
window.playersToResolve = playersToResolve.slice(MAX_RESOLVE_PLAYERS_PER_REQUEST);
var d = {guids: p};
window.playersInResolving = window.playersInResolving.concat(p);
postAjax('getPlayersByGuids', d, function(dat) {
var resolvedName = {};
if(dat.result) {
$.each(dat.result, function(ind, player) {
window.setPlayerName(player.guid, player.nickname);
resolvedName[player.guid] = player.nickname;
// remove from array
window.playersInResolving.splice(window.playersInResolving.indexOf(player.guid), 1);
});
} else {
//no 'result' - a successful http request, but the returned result was an error of some kind
console.warn('getplayers problem - no result in response: '+dat);
//likely to be some kind of 'bad request' (e.g. too many names at once, or otherwise badly formatted data.
//therefore, not a good idea to automatically retry by adding back to the playersToResolve list
}
// Run hook 'playerNameResolved' with the resolved player names
window.runHooks('playerNameResolved', {names: resolvedName});
//TODO: have an event triggered for this instead of hard-coded single function call
if(window.selectedPortal)
window.renderPortalDetails(window.selectedPortal);
//if more to do, run again
if(window.playersToResolve.length>0) resolvePlayerNames();
},
function() {
// append failed resolves to the list again
console.warn('resolving player guids failed: ' + p.join(', '));
window.playersToResolve.concat(p);
});
}
window.setPlayerName = function(guid, nick, uncertain) {
// the 'uncertain' flag is set when we're scrolling back through chat. it's possible in this case
// to come across a message from before a name change. these should be ignored if existing cache entries exist
if(uncertain && guid in sessionStorage) return;
if($.trim(('' + nick)).slice(0, 5) === '{"L":' && !window.alertFor37WasShown) {
window.alertFor37WasShown = true;
alert('You have run into bug #37. Please help me solve it!\nCopy and paste this text and post it here:\nhttps://github.com/breunigs/ingress-intel-total-conversion/issues/37\nIf copy & pasting doesnt work, make a screenshot instead.\n\n\n' + window.debug.printStackTrace() + '\n\n\n' + JSON.stringify(nick));
}
sessionStorage[guid] = nick;
// IITC needs our own player ID early on in startup. the only way we can find this is by something else
// doing a guid->name lookup for our own name. as this doesn't always happen - and likely won't happen when needed
// we'll store our own name->guid lookup in localStorage
if (nick == PLAYER.nickname) {
localStorage['PLAYER-'+PLAYER.nickname] = guid;
PLAYER.guid = guid; // set it in PLAYER in case it wasn't already done
}
}
// test to see if a specific player GUID is a special system account (e.g. __JARVIS__, __ADA__) that shouldn't
// be listed as a player
window.isSystemPlayer = function(guid) {
window.isSystemPlayer = function(name) {
switch (guid) {
case '00000000000000000000000000000001.c':
case '00000000000000000000000000000002.c':
switch (name) {
case '__ADA__':
case '__JARVIS__':
return true;
default:
return false;
}
}

81
code/portal_data.js Normal file
View File

@ -0,0 +1,81 @@
/// PORTAL DATA TOOLS ///////////////////////////////////////////////////
// misc functions to get portal info
// search through the links data for all that link from or to a portal. returns an object with separate lists of in
// and out links. may or may not be as accurate as the portal details, depending on how much data the API returns
window.getPortalLinks = function(guid) {
var links = { in: [], out: [] };
$.each(window.links, function(g,l) {
var d = l.options.data;
if (d.oGuid == guid) {
links.out.push(g);
}
if (d.dGuid == guid) {
links.in.push(g);
}
});
return links;
}
// search through the fields for all that reference a portal
window.getPortalFields = function(guid) {
var fields = [];
$.each(window.fields, function(g,f) {
var d = f.options.data;
if ( d.points[0].guid == guid
|| d.points[1].guid == guid
|| d.points[2].guid == guid ) {
fields.push(g);
}
});
return fields;
}
// find the lat/lon for a portal, using any and all available data
// (we have the list of portals, the cached portal details, plus links and fields as sources of portal locations)
window.findPortalLatLng = function(guid) {
if (window.portals[guid]) {
return window.portals[guid].getLatLng();
}
// not found in portals - try the cached (and possibly stale) details - good enough for location
var details = portalDetail.get(guid);
if (details) {
return L.latLng (details.locationE6.latE6/1E6, details.locationE6.lngE6/1E6);
}
// now try searching through fields
for (var fguid in window.fields) {
var f = window.fields[fguid].options.data;
for (var i in f.points) {
if (f.points[i].guid == guid) {
return L.latLng (f.points[i].latE6/1E6, f.points[i].lngE6/1E6);
}
}
}
// and finally search through links
for (var lguid in window.links) {
var l = window.links[lguid].options.data;
if (l.oGuid == guid) {
return L.latLng (l.oLatE6/1E6, l.oLngE6/1E6);
}
if (l.dGuid == guid) {
return L.latLng (l.dLatE6/1E6, l.dLngE6/1E6);
}
}
// no luck finding portal lat/lng
return undefined;
}

59
code/portal_detail.js Normal file
View File

@ -0,0 +1,59 @@
/// PORTAL DETAIL //////////////////////////////////////
// code to retrieve the new potal detail data from the servers
// NOTE: the API for portal detailed information is NOT FINAL
// this is a temporary measure to get things working again after a major change to the intel map
// API. expect things to change here
// anonymous function wrapper for the code - any variables/functions not placed into 'window' will be private
(function(){
var cache;
window.portalDetail = function() {};
window.portalDetail.setup = function() {
cache = new DataCache();
cache.startExpireInterval(20);
}
window.portalDetail.get = function(guid) {
return cache.get(guid);
}
window.portalDetail.isFresh = function(guid) {
return cache.isFresh(guid);
}
var handleResponse = function(guid, data, success) {
if (success) {
cache.store(guid,data);
//FIXME..? better way of handling sidebar refreshing...
if (guid == selectedPortal) {
renderPortalDetails(guid);
}
}
window.runHooks ('portalDetailLoaded', {guid:guid, success:success, details:data});
}
window.portalDetail.request = function(guid) {
window.postAjax('getPortalDetails', {guid:guid},
function(data,textStatus,jqXHR) { handleResponse(guid, data, true); },
function() { handleResponse(guid, undefined, false); }
);
}
})(); // anonumous wrapper function end

View File

@ -5,79 +5,45 @@
window.renderPortalDetails = function(guid) {
selectPortal(window.portals[guid] ? guid : null);
if (!portalDetail.isFresh(guid)) {
portalDetail.request(guid);
}
// TODO? handle the case where we request data for a particular portal GUID, but it *isn't* in
// window.portals....
if(!window.portals[guid]) {
urlPortal = guid;
$('#portaldetails').html('');
if(isSmartphone()) {
$('.fullimg').remove();
$('#mobileinfo').html('');
$('#mobileinfo').html('<div style="text-align: center"><b>tap here for info screen</b></div>');
}
return;
}
var d = window.portals[guid].options.details;
// collect some random data thats not worth to put in an own method
var links = {incoming: 0, outgoing: 0};
if(d.portalV2.linkedEdges) $.each(d.portalV2.linkedEdges, function(ind, link) {
links[link.isOrigin ? 'outgoing' : 'incoming']++;
});
function linkExpl(t) { return '<tt title="↳ incoming links\n↴ outgoing links\n• is the portal">'+t+'</tt>'; }
var linksText = [linkExpl('links'), linkExpl(' ↳ ' + links.incoming+'&nbsp;&nbsp;•&nbsp;&nbsp;'+links.outgoing+' ↴')];
var player = d.captured && d.captured.capturingPlayerId
? '<span class="nickname">' + getPlayerName(d.captured.capturingPlayerId) + '</span>'
: null;
var playerText = player ? ['owner', player] : null;
var time = d.captured
? '<span title="' + unixTimeToDateTimeString(d.captured.capturedTime, false) + '\n'
+ formatInterval(Math.floor((Date.now()-d.captured.capturedTime)/1000), 2) + ' ago">'
+ unixTimeToString(d.captured.capturedTime) + '</span>'
: null;
var sinceText = time ? ['since', time] : null;
var linkedFields = ['fields', d.portalV2.linkedFields ? d.portalV2.linkedFields.length : 0];
// collect and html-ify random data
var randDetails = [
playerText, sinceText,
getRangeText(d), getEnergyText(d),
linksText, getAvgResoDistText(d),
linkedFields, getAttackApGainText(d),
getHackDetailsText(d), getMitigationText(d)
];
// artifact details
//niantic hard-code the fact it's just jarvis shards/targets - so until more examples exist, we'll do the same
//(at some future point we can iterate through all the artifact types and add rows as needed)
var jarvisArtifact = artifact.getPortalData (guid, 'jarvis');
if (jarvisArtifact) {
// the genFourColumnTable function below doesn't handle cases where one column is null and the other isn't - so default to *something* in both columns
var target = ['',''], shards = ['shards','(none)'];
if (jarvisArtifact.target) {
target = ['target', '<span class="'+TEAM_TO_CSS[jarvisArtifact.target]+'">'+(jarvisArtifact.target==TEAM_RES?'Resistance':'Enlightened')+'</span>'];
}
if (jarvisArtifact.fragments) {
shards = [jarvisArtifact.fragments.length>1?'shards':'shard', '#'+jarvisArtifact.fragments.join(', #')];
}
randDetails.push (target, shards);
}
var portal = window.portals[guid];
var data = portal.options.data;
var details = portalDetail.get(guid);
randDetails = '<table id="randdetails">' + genFourColumnTable(randDetails) + '</table>';
var modDetails = details ? '<div class="mods">'+getModDetails(details)+'</div>' : '';
var miscDetails = details ? getPortalMiscDetails(guid,details) : '';
var resoDetails = details ? getResonatorDetails(details) : '';
var resoDetails = '<table id="resodetails">' + getResonatorDetails(d) + '</table>';
//TODO? other status details...
var statusDetails = details ? '' : '<div id="portalStatus">Loading details...</div>';
var img = getPortalImageUrl(d);
var lat = d.locationE6.latE6/1E6;
var lng = d.locationE6.lngE6/1E6;
var perma = '/intel?ll='+lat+','+lng+'&z=17&pll='+lat+','+lng;
var imgTitle = 'title="'+getPortalDescriptionFromDetails(d)+'\n\nClick to show full image."';
var poslinks = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(d.portalV2.descriptiveText.TITLE)+'\')';
var portalDetailObj = window.getPortalDescriptionFromDetailsExtended(d);
var img = fixPortalImageUrl(details ? details.imageByUrl && details.imageByUrl.imageUrl : data.image);
var title = details ? details.portalV2.descriptiveText.TITLE : data.title;
var lat = data.latE6/1E6;
var lng = data.lngE6/1E6;
var imgTitle = details ? getPortalDescriptionFromDetails(details) : data.title;
imgTitle += '\n\nClick to show full image.';
var portalDetailObj = details ? window.getPortalDescriptionFromDetailsExtended(details) : undefined;
var portalDetailedDescription = '';
@ -111,74 +77,184 @@ window.renderPortalDetails = function(guid) {
portalDetailedDescription += '</table>';
}
var levelDetails = getPortalLevel(d);
if(levelDetails != 8) {
if(levelDetails==Math.ceil(levelDetails))
levelDetails += "\n8";
else
levelDetails += "\n" + (Math.ceil(levelDetails) - levelDetails)*8;
levelDetails += " resonator level(s) needed for next portal level";
} else {
levelDetails += "\nfully upgraded";
// portal level. start with basic data - then extend with fractional info in tooltip if available
var levelInt = data ? data.level : getPortalLevel(details);
var levelDetails = data.level;
if (details) {
levelDetails = getPortalLevel(details);
if(levelDetails != 8) {
if(levelDetails==Math.ceil(levelDetails))
levelDetails += "\n8";
else
levelDetails += "\n" + (Math.ceil(levelDetails) - levelDetails)*8;
levelDetails += " resonator level(s) needed for next portal level";
} else {
levelDetails += "\nfully upgraded";
}
}
levelDetails = "Level " + levelDetails;
var linkDetails = [];
var posOnClick = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(title)+'\')';
var permalinkUrl = '/intel?ll='+lat+','+lng+'&z=17&pll='+lat+','+lng;
if (typeof android !== 'undefined' && android && android.intentPosLink) {
// android devices. one share link option - and the android app provides an interface to share the URL,
// share as a geo: intent (navigation via google maps), etc
var shareLink = $('<div>').html( $('<a>').attr({onclick:posOnClick}).text('Share portal') ).html();
linkDetails.push('<aside>'+shareLink+'</aside>');
} else {
// non-android - a permalink for the portal
var permaHtml = $('<div>').html( $('<a>').attr({href:permalinkUrl, target:'_blank', title:'Create a URL link to this portal'}).text('Portal link') ).html();
linkDetails.push ( '<aside>'+permaHtml+'</aside>' );
// and a map link popup dialog
var mapHtml = $('<div>').html( $('<a>').attr({onclick:posOnClick, title:'Link to alternative maps (Google, etc)'}).text('Map links') ).html();
linkDetails.push('<aside>'+mapHtml+'</aside>');
}
$('#portaldetails')
.attr('class', TEAM_TO_CSS[getTeam(d)])
.html(''
+ '<h3 class="title">'+escapeHtmlSpecialChars(d.portalV2.descriptiveText.TITLE)+'</h3>'
+ '<span class="close" onclick="renderPortalDetails(null); if(isSmartphone()) show(\'map\');" title="Close">X</span>'
.html('') //to ensure it's clear
.attr('class', TEAM_TO_CSS[portal.options.team])
.append(
$('<h3>').attr({class:'title'}).text(data.title),
$('<span>').attr({class:'close', onclick:'renderPortalDetails(null); if(isSmartphone()) show("map");',title:'Close'}).text('X'),
// help cursor via ".imgpreview img"
+ '<div class="imgpreview" '+imgTitle+' style="background-image: url('+img+')">'
+ '<span id="level" title="'+levelDetails+'">'+Math.floor(getPortalLevel(d))+'</span>'
+ '<div class="portalDetails">'+ portalDetailedDescription + '</div>'
+ '<img class="hide" src="'+img+'"/></div>'
+ '</div>'
+ '<div class="mods">'+getModDetails(d)+'</div>'
+ randDetails
+ resoDetails
+ '<div class="linkdetails">'
+ (
typeof android !== 'undefined' && android && android.intentPosLink // Android handles both links via a dialog
? '<aside><a onclick="'+poslinks+'" title="Create a URL link to this portal" >Portal link</a></aside>'
: '<aside><a href="'+perma+'" onclick="return androidCopy(this.href)" title="Create a URL link to this portal" >Portal link</a></aside>'
+ '<aside><a onclick="'+poslinks+'" title="Link to alternative maps (Google, etc)">Map links</a></aside>'
)
+ '</div>'
$('<div>')
.attr({class:'imgpreview', title:imgTitle, style:"background-image: url('"+img+"')"})
.append(
$('<span>').attr({id:'level', title: levelDetails}).text(levelInt),
$('<div>').attr({class:'portalDetails'}).html(portalDetailedDescription),
$('<img>').attr({class:'hide', src:img})
),
modDetails,
miscDetails,
resoDetails,
statusDetails,
'<div class="linkdetails">' + linkDetails.join('') + '</div>'
);
// try to resolve names that were required for above functions, but
// weren't available yet.
resolvePlayerNames();
runHooks('portalDetailsUpdated', {portalDetails: d});
// only run the hooks when we have a portalDetails object - most plugins rely on the extended data
// TODO? another hook to call always, for any plugins that can work with less data?
if (details) {
runHooks('portalDetailsUpdated', {guid: guid, portal: portal, portalDetails: details, portalData: data});
}
}
window.getPortalMiscDetails = function(guid,d) {
var randDetails;
if (d) {
// collect some random data thats not worth to put in an own method
var links = {incoming: 0, outgoing: 0};
$.each(d.portalV2.linkedEdges||[], function(ind, link) {
links[link.isOrigin ? 'outgoing' : 'incoming']++;
});
function linkExpl(t) { return '<tt title="↳ incoming links\n↴ outgoing links\n• is the portal">'+t+'</tt>'; }
var linksText = [linkExpl('links'), linkExpl(' ↳ ' + links.incoming+'&nbsp;&nbsp;•&nbsp;&nbsp;'+links.outgoing+' ↴')];
var player = d.captured && d.captured.capturingPlayerId
? '<span class="nickname">' + d.captured.capturingPlayerId + '</span>'
: null;
var playerText = player ? ['owner', player] : null;
var time = d.captured
? '<span title="' + unixTimeToDateTimeString(d.captured.capturedTime, false) + '\n'
+ formatInterval(Math.floor((Date.now()-d.captured.capturedTime)/1000), 2) + ' ago">'
+ unixTimeToString(d.captured.capturedTime) + '</span>'
: null;
var sinceText = time ? ['since', time] : null;
var linkedFields = ['fields', d.portalV2.linkedFields ? d.portalV2.linkedFields.length : 0];
// collect and html-ify random data
var randDetailsData = [];
if (playerText && sinceText) {
randDetailsData.push (playerText, sinceText);
}
randDetailsData.push (
getRangeText(d), getEnergyText(d),
linksText, getAvgResoDistText(d),
linkedFields, getAttackApGainText(d),
getHackDetailsText(d), getMitigationText(d)
);
// artifact details
//niantic hard-code the fact it's just jarvis shards/targets - so until more examples exist, we'll do the same
//(at some future point we can iterate through all the artifact types and add rows as needed)
var jarvisArtifact = artifact.getPortalData (guid, 'jarvis');
if (jarvisArtifact) {
// the genFourColumnTable function below doesn't handle cases where one column is null and the other isn't - so default to *something* in both columns
var target = ['',''], shards = ['shards','(none)'];
if (jarvisArtifact.target) {
target = ['target', '<span class="'+TEAM_TO_CSS[jarvisArtifact.target]+'">'+(jarvisArtifact.target==TEAM_RES?'Resistance':'Enlightened')+'</span>'];
}
if (jarvisArtifact.fragments) {
shards = [jarvisArtifact.fragments.length>1?'shards':'shard', '#'+jarvisArtifact.fragments.join(', #')];
}
randDetailsData.push (target, shards);
}
randDetails = '<table id="randdetails">' + genFourColumnTable(randDetailsData) + '</table>';
}
return randDetails;
}
// draws link-range and hack-range circles around the portal with the
// given details. Clear them if parameter 'd' is null.
window.setPortalIndicators = function(d) {
window.setPortalIndicators = function(p) {
if(portalRangeIndicator) map.removeLayer(portalRangeIndicator);
portalRangeIndicator = null;
if(portalAccessIndicator) map.removeLayer(portalAccessIndicator);
portalAccessIndicator = null;
if(d === null) return;
// if we have a portal...
var range = getPortalRange(d);
var coord = [d.locationE6.latE6/1E6, d.locationE6.lngE6/1E6];
portalRangeIndicator = (range.range > 0
? L.geodesicCircle(coord, range.range, {
fill: false,
color: RANGE_INDICATOR_COLOR,
weight: 3,
dashArray: range.isLinkable ? undefined : "10,10",
clickable: false })
: L.circle(coord, range.range, { fill: false, stroke: false, clickable: false })
if(p) {
var coord = p.getLatLng();
// range is only known for sure if we have portal details
// TODO? render a min range guess until details are loaded..?
var d = portalDetail.get(p.options.guid);
if (d) {
var range = getPortalRange(d);
portalRangeIndicator = (range.range > 0
? L.geodesicCircle(coord, range.range, {
fill: false,
color: RANGE_INDICATOR_COLOR,
weight: 3,
dashArray: range.isLinkable ? undefined : "10,10",
clickable: false })
: L.circle(coord, range.range, { fill: false, stroke: false, clickable: false })
).addTo(map);
}
portalAccessIndicator = L.circle(coord, HACK_RANGE,
{ fill: false, color: ACCESS_INDICATOR_COLOR, weight: 2, clickable: false }
).addTo(map);
}
portalAccessIndicator = L.circle(coord, HACK_RANGE,
{ fill: false, color: ACCESS_INDICATOR_COLOR, weight: 2, clickable: false }
).addTo(map);
}
// highlights portal with given GUID. Automatically clears highlights
@ -205,7 +281,7 @@ window.selectPortal = function(guid) {
}
}
setPortalIndicators(newPortal ? newPortal.options.details : null);
setPortalIndicators(newPortal);
runHooks('portalSelected', {selectedPortalGuid: guid, unselectedPortalGuid: oldPortalGuid});
return update;

View File

@ -29,8 +29,8 @@ window.getPortalDescriptionFromDetails = function(details) {
var desc = descObj.TITLE;
if(descObj.ADDRESS)
desc += '\n' + descObj.ADDRESS;
if(descObj.ATTRIBUTION)
desc += '\nby '+descObj.ATTRIBUTION+' ('+descObj.ATTRIBUTION_LINK+')';
// if(descObj.ATTRIBUTION)
// desc += '\nby '+descObj.ATTRIBUTION+' ('+descObj.ATTRIBUTION_LINK+')';
return desc;
}
@ -102,7 +102,7 @@ window.getModDetails = function(d) {
modTooltip = modName + '\n';
if (mod.installingUser) {
modTooltip += 'Installed by: '+ getPlayerName(mod.installingUser) + '\n';
modTooltip += 'Installed by: '+ mod.installingUser + '\n';
}
if (mod.stats) {
@ -176,7 +176,7 @@ window.getResonatorDetails = function(d) {
var l = parseInt(reso.level);
var v = parseInt(reso.energyTotal);
var nick = window.getPlayerName(reso.ownerGuid);
var nick = reso.ownerGuid;
var dist = reso.distanceToPortal;
// if array order and slot order drift apart, at least the octant
// naming will still be correct.
@ -184,7 +184,8 @@ window.getResonatorDetails = function(d) {
resoDetails.push(renderResonatorDetails(slot, l, v, dist, nick));
});
return genFourColumnTable(resoDetails);
return '<table id="resodetails">' + genFourColumnTable(resoDetails) + '</table>';
}
// helper function that renders the HTML for a given resonator. Does

View File

@ -112,7 +112,8 @@ window.getAttackApGain = function(d) {
return true;
resoCount += 1;
var reslevel=parseInt(reso.level);
if(reso.ownerGuid === PLAYER.guid) {
// NOTE: reso.ownerGuid is actually the name - no player GUIDs are visible in the protocol any more
if(reso.ownerGuid === PLAYER.nickname) {
if(maxResonators[reslevel] > 0) {
maxResonators[reslevel] -= 1;
}
@ -167,7 +168,8 @@ window.potentialPortalLevel = function(d) {
player_resontators[i] = i > PLAYER.level ? 0 : MAX_RESO_PER_PLAYER[i];
}
$.each(resonators_on_portal, function(ind, reso) {
if(reso !== null && reso.ownerGuid === window.PLAYER.guid) {
// NOTE: reso.ownerGuid is actually the player name - GUIDs are not in the protocol any more
if(reso !== null && reso.ownerGuid === window.PLAYER.nickname) {
player_resontators[reso.level]--;
}
resonator_levels.push(reso === null ? 0 : reso.level);
@ -194,10 +196,8 @@ window.potentialPortalLevel = function(d) {
}
window.getPortalImageUrl = function(d) {
if (d.imageByUrl && d.imageByUrl.imageUrl) {
url = d.imageByUrl.imageUrl;
window.fixPortalImageUrl = function(url) {
if (url) {
if (window.location.protocol === 'https:') {
url = url.indexOf('www.panoramio.com') !== -1
? url.replace(/^http:\/\/www/, 'https://ssl').replace('small', 'medium')

View File

@ -281,7 +281,7 @@ window.getMinPortalLevelForZoom = function(z) {
// these values are from the stock intel map. however, they're too detailed for reasonable speed, and increasing
// detail at a higher zoom level shows enough detail still, AND speeds up IITC considerably
//var ZOOM_TO_LEVEL = [8, 8, 8, 8, 7, 7, 6, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1];
var ZOOM_TO_LEVEL = [8, 8, 8, 8, 8, 8, 7, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1];
var ZOOM_TO_LEVEL = [8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1];
var l = ZOOM_TO_LEVEL[z] || 0;
return l;

View File

@ -0,0 +1,247 @@
// artifacts - uses the same cut-down data format as the map portal data
{
"artifacts":[
{
"targetInfos":[
{
"portalInfo":{
"title":"Cupid's Span",
"image":"http://lh6.ggpht.com/xBckx2qeAv4kog4JQfUxzzq86OG0RYP2ccrQv05HOuMeqUWV2cGMWrBU27LZJKUCSNCdQVAt3eqtnBlPGhyB",
"level":5,
"latE6":37791541,
"health":100.0,
"resCount":8,
"lngE6":-122390014,
"team":"ENLIGHTENED",
"type":"portal"
},
"portalGuid":"9f2eaaa0c1ae4204a2ba5edd46ad4c95.12",
"team":"ENLIGHTENED"
},
{
"portalInfo":{
"title":"Pir\u00e1mide de Mayo",
"image":"http://lh6.ggpht.com/_3aFkA6XnDw502tysY7llc5rCCq--A-B7JtYckuKk48lyPo73MyMRd6PayGLFk6WckN-z8Rffnyw5rdojTE81A",
"level":6,
"latE6":-34608403,
"health":100.0,
"resCount":8,
"lngE6":-58372164,
"team":"ENLIGHTENED",
"type":"portal"
},
"portalGuid":"6899fca3412a41fc97a509fa6030b0bf.12",
"team":"RESISTANCE"
}
],
"fragmentInfos":[
{
"portalInfo":{
"title":"Kinesis Wellness Water Fountain",
"image":"http://lh5.ggpht.com/qrczaveosQtJW9HcQX0PPobh9Q3dJEfQ_weumBjKbtG1M5zQ8OmGHQCy4SRjUGofEz5KuES6N0ox6guBKp_n",
"level":1,
"latE6":1509661,
"health":0,
"resCount":0,
"lngE6":110362028,
"team":"NEUTRAL",
"type":"portal"
},
"fragments":[
7
],
"portalGuid":"caf18e11731046e4a4c2fd9246abea4f.16"
},
{
"portalInfo":{
"title":"Statue 2",
"image":"http://lh5.ggpht.com/96RZXGomxTRD_F6pMFIm3Lbxibs6RBz9YZ4vQLAIzZ5CRuR-FL0YNs8oy6Mz6zfmq6PTrFI-LZ_59HM3bYzZ",
"level":7,
"latE6":31200954,
"health":55.0,
"resCount":8,
"lngE6":29950883,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
10
],
"portalGuid":"5e7fa56871d14e69a8a943a448e11889.16"
},
{
"portalInfo":{
"title":"\u30a4\u30eb\u30ab\u306e\u6c34\u9053",
"image":"http://lh3.ggpht.com/VOKphdag3JMRykYIgVFPFPlyXiGpRMift2XtRKcMFwg9zoErFKD-63AOFe_KU9JZtc8acGVS6x9FMRLKRhI",
"level":5,
"latE6":33681143,
"health":100.0,
"resCount":8,
"lngE6":135345213,
"team":"ENLIGHTENED",
"type":"portal"
},
"fragments":[
4
],
"portalGuid":"05aa702ee9174e53a1c4659d1d070fc2.16"
},
{
"portalInfo":{
"title":"Church of South India",
"image":"http://lh3.ggpht.com/ngJhP9Q6b8LqfaRqMncRjjGxbX2NQoG65GUPAYZPHOKmW6ItJw408SShv7GPBmF02VmqSvxS2q8PTwa7XHNp",
"level":6,
"latE6":11002728,
"health":100.0,
"resCount":8,
"lngE6":76976030,
"team":"ENLIGHTENED",
"type":"portal"
},
"fragments":[
3
],
"portalGuid":"f67814a00408447397edaab01529f972.16"
},
{
"portalInfo":{
"title":"Corvo Windmill",
"image":"http://lh5.ggpht.com/FRnWem84CCFT4VJdPA12_cj7zeEu9kFoak0EWbr8ELWj--FKPgvpXymrvCqbjnE48M_S2vWWBg7DNe6eGZCL",
"level":5,
"latE6":39670135,
"health":100.0,
"resCount":8,
"lngE6":-31113994,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
2
],
"portalGuid":"16e688dde1084251b762a96bd05892a6.16"
},
{
"portalInfo":{
"title":"\u0421\u043b\u0430\u0432\u0430 \u0413\u0435\u0440\u043e\u044f\u043c \u0413\u0440\u0430\u0436\u0434\u0430\u043d\u0441\u043a\u043e\u0439 \u0412\u043e\u0439\u043d\u044b",
"image":"http://lh6.ggpht.com/yD-0HgkNyEcZ3f5g6-01MIGskkUdFNoSXq8EkyWINJdZEXnEoT7Qd3tWL80fzKyK52vZZRnX3VVNuJzPGGaxGw",
"level":5,
"latE6":61723385,
"health":100.0,
"resCount":8,
"lngE6":129480552,
"team":"ENLIGHTENED",
"type":"portal"
},
"fragments":[
12
],
"portalGuid":"539e8816c9774fad9d1f5da30da15236.16"
},
{
"portalInfo":{
"title":"US Post Office",
"image":"",
"level":1,
"latE6":43568894,
"health":0,
"resCount":0,
"lngE6":-101661386,
"team":"NEUTRAL",
"type":"portal"
},
"fragments":[
1
],
"portalGuid":"075f54d4e7cb408eb181de704b291e00.12"
},
{
"portalInfo":{
"title":"Colegio Oficial De Aquitectos De Canarias",
"image":"http://www.panoramio.com/photos/small/7680566.jpg",
"level":7,
"latE6":28475279,
"health":85.0,
"resCount":8,
"lngE6":-16250839,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
9
],
"portalGuid":"61e745cab2f6415dbb9d97b5cf01ab22.12"
},
{
"portalInfo":{
"title":"Ricardo Ugarte \"Lorea\" 1973",
"image":"http://lh4.ggpht.com/r9aaw6LcBqwUDbkMv781mWmtNpq_vzqGajCcdGbMMGN00KC1P_YMJBOzevMFAT0WwZHONfsu_f49m7HTLUl93C1Pt6DggdQZw7Kxi1VSohksRFUXIw",
"level":8,
"latE6":28472611,
"health":100.0,
"resCount":8,
"lngE6":-16255785,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
8
],
"portalGuid":"08c321d96dd841a39b69c9bb58bc7d7e.16"
},
{
"portalInfo":{
"title":"Street Art L\u00e9zard",
"image":"http://lh5.ggpht.com/3CR9Ak8-bq42Ahx-i8Od_ERJxnfllwq_aZ8Ndd86RrlejiIHIjdlg7tsxQeo0PZ2vMoe8F4fkPmV-VO710pK",
"level":6,
"latE6":-22157401,
"health":42.0,
"resCount":8,
"lngE6":166448768,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
6
],
"portalGuid":"f854e60da70849b486ffd1eca238ba22.16"
},
{
"portalInfo":{
"title":"Estaci\u00f3n de Ferrocarril Mitre",
"image":"http://lh3.ggpht.com/6SBiNwknx2EjjNeaKHoegv1YaXzFsIL1wgSB0eeFehRjx3UpsWV2BJmn6_9KpOaWpkoXtq7QoVJqCrPO7ulXCsSU7givtJ3zWFr7ehU2BMIKYKQs",
"level":2,
"latE6":-26820833,
"health":84.0,
"resCount":8,
"lngE6":-65200000,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
11
],
"portalGuid":"ed88b9f4904041d8a384ac3a9cc90d7d.11"
},
{
"portalInfo":{
"title":"\u05d0\u05e8\u05db\u05d9\u05d5\u05df \u05d4\u05de\u05d5\u05e9\u05d1\u05d4 \u05d9\u05e1\u05d5\u05d3 \u05d4\u05de\u05e2\u05dc\u05d4 ",
"image":"http://lh5.ggpht.com/eB6juKp3dpj6a83c_g0ZBia-nDM8Gxns4c0uQaePqD2o7c5Cf82QBXy2Ceea-MiovDXaLEkpMQVXSgTRwmSzXw",
"level":6,
"latE6":33058575,
"health":100.0,
"resCount":8,
"lngE6":35612649,
"team":"RESISTANCE",
"type":"portal"
},
"fragments":[
5
],
"portalGuid":"d911ef545cad44e6ae3e01ada3ceed1b.16"
}
],
"artifactId":"jarvis"
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +0,0 @@
[
"431a30b634394956a16e62954222a37d.d",
1360634878999,
{
"plext": {
"text": "Control Field @In the fishing village ( Lomse (Oktyabr'skaya ulitsa, 1, Kaliningrad, Kaliningrad Oblast, Russia) has decayed -108 MUs",
"markup": [
[
"TEXT",
{
"plain": "Control Field @"
}
],
[
"PORTAL",
{
"name": "In the fishing village ( Lomse",
"plain": "In the fishing village ( Lomse (Oktyabr'skaya ulitsa, 1, Kaliningrad, Kaliningrad Oblast, Russia)",
"team": "ALIENS",
"latE6": 54705182,
"address": "Oktyabr'skaya ulitsa, 1, Kaliningrad, Kaliningrad Oblast, Russia",
"lngE6": 20514959,
"guid": "6af16d09fb574c989b7fa09e718585a7.12"
}
],
[
"TEXT",
{
"plain": " has decayed -"
}
],
[
"TEXT",
{
"plain": "108"
}
],
[
"TEXT",
{
"plain": " MUs"
}
]
],
"plextType": "SYSTEM_BROADCAST",
"team": "NEUTRAL"
}
}
]

View File

@ -1,13 +0,0 @@
// http://www.ingress.com/rpc/dashboard.sendPlext
// posting:
{"message":"x","latE6":73689520,"lngE6":95322756,"factionOnly":true,"method":"dashboard.sendPlext"}
{"message":"x","latE6":73689520,"lngE6":95322756,"method":"dashboard.sendPlext"}
// faction response:
{"gameBasket": {"deletedEntityGuids": [], "gameEntities": [], "inventory": []}, "result": "c709d0aa51664510a43c635d5df919cf.d"}
// public response:
{"gameBasket": {"deletedEntityGuids": [], "gameEntities": [], "inventory": []}, "result": "1b113466f403499191eae568915b7cc9.d"}

View File

@ -1,39 +0,0 @@
[
"98def9ad4f3a4c30908ad1dff5638c6c.b",
1360156123960,
{
"controllingTeam": {
"team": "RESISTANCE"
},
"capturedRegion": {
"vertexA": {
"guid": "c2afe403edca4114b8c724a46d23959c.11",
"location": {
"lngE6": 8687448,
"latE6": 49406850
}
},
"vertexC": {
"guid": "e1d616018f0647afb985a20fc9d7baa5.11",
"location": {
"lngE6": 8684374,
"latE6": 49408196
}
},
"vertexB": {
"guid": "cd4a44d7684e4d40a5754540fd7686b4.11",
"location": {
"lngE6": 8688377,
"latE6": 49406900
}
}
},
"entityScore": {
"entityScore": "4"
},
"creator": {
"creatorGuid": "8d684d38d2654c8b971ff56b9f3c8895.c",
"creationTime": "1360156123445"
}
}
]

View File

@ -0,0 +1,16 @@
// get_portal_details - request
// note the munged parameters
// also excess 'junk' parameters to obsfucate the request - the only ones needed are the first three
// (guid, method name, version parameter)
{
"seg6ohxgnqf9xu9w":"56d5b86428c84aadac0d6214eff81f60.11",
"yyngyttbmmbuvdpa":"c00thnhf1yp3z6mn",
"avz401t36lzrapis":"c5d0a5d608f729a1232bebdc12fb86ba5fb6c43f",
"nzd23jqm9k1cnnij":67,
"0dod6onpa1s4fezp":-90000000,
"soass3t7mm7anneo":-180000000,
"cvarmr3o00ngylo1":90000000,
"udzwnlx07hzd3bfo":180000000
}

View File

@ -0,0 +1,129 @@
// get_portal_details - response
// note no player GUIDs any more - resonators[].ownerGuid is actually a name
{
"resonatorArray":{
"resonators":[
{
"slot":0,
"level":7,
"energyTotal":5000,
"distanceToPortal":33,
"id":"cc5416d0-d894-47ee-b23b-47d761f0486b",
"ownerGuid":"dt11"
},
{
"slot":1,
"level":6,
"energyTotal":4000,
"distanceToPortal":34,
"id":"b90874a2-0157-4033-8dac-0ee21c1c513b",
"ownerGuid":"dt11"
},
{
"slot":2,
"level":5,
"energyTotal":3000,
"distanceToPortal":34,
"id":"f96d96b6-cdb0-4217-be58-34ac8ea82415",
"ownerGuid":"dt11"
},
{
"slot":3,
"level":4,
"energyTotal":2500,
"distanceToPortal":35,
"id":"8dc8f746-13a7-4730-b0d0-25b75784a090",
"ownerGuid":"dt11"
},
{
"slot":4,
"level":4,
"energyTotal":2500,
"distanceToPortal":33,
"id":"ae65fd13-c9cf-412b-93b4-65e9a71ef5d6",
"ownerGuid":"dt11"
},
{
"slot":5,
"level":4,
"energyTotal":2500,
"distanceToPortal":34,
"id":"d0a4ee3e-ab78-424f-bafc-da1da2423d0a",
"ownerGuid":"dt11"
},
{
"slot":6,
"level":5,
"energyTotal":3000,
"distanceToPortal":34,
"id":"09458b16-ccea-4f64-80ee-e2848f51b090",
"ownerGuid":"dt11"
},
{
"slot":7,
"level":6,
"energyTotal":4000,
"distanceToPortal":34,
"id":"05f77a0e-ccc9-4f6a-8fbf-07b0010a02c2",
"ownerGuid":"dt11"
}
]
},
"locationE6":{
"lngE6":-148266,
"latE6":51511550
},
"controllingTeam":{
"team":"ENLIGHTENED"
},
"portalV2":{
"linkedEdges":[
{
"otherPortalGuid":"bfcb133c0f3a43909be288eb27cf5968.16",
"edgeGuid":"dd3b4868cb74469aa69399b775ff8e48.9",
"isOrigin":true
},
{
"otherPortalGuid":"8a094798b0a54b9d81cc2992edbd53e1.11",
"edgeGuid":"c9c4ecc18ac24163bb937b86b48902dc.9",
"isOrigin":true
}
],
"linkedModArray":[
{
"installingUser":"dt11",
"displayName":"Portal Shield",
"type":"RES_SHIELD",
"stats":{
"REMOVAL_STICKINESS":"0",
"MITIGATION":"20"
},
"rarity":"RARE"
},
{
"installingUser":"dt11",
"displayName":"Portal Shield",
"type":"RES_SHIELD",
"stats":{
"REMOVAL_STICKINESS":"0",
"MITIGATION":"10"
},
"rarity":"COMMON"
},
null,
null
],
"descriptiveText":{
"TITLE":"Mayfair Post Office, London",
"ADDRESS":"32 Grosvenor Street, London, Greater London W1K 4QS, UK"
}
},
"imageByUrl":{
"imageUrl":"http://lh5.ggpht.com/5963D4ATz31LG-zWuPSWrdUKqq_u09-C-GNcyNd6vH1isg7PQjax2niQ5LbZfAwnjnB4DJITWbfuGeMH0MnDqThnmI_CNWIQ2euXk8Cwjls0yXO88A"
},
"captured":{
"capturedTime":"1385754854932",
"capturingPlayerId":"dt11"
}
}

View File

@ -0,0 +1,20 @@
// a request for map data - note the munged random strings for parameter names, and also
// a set of additional junk parameters that have nothing to do with this request. Only the first
// three entries are relevant - the first is the set of quadkeys for the map tiles,
// the next is the method name, and finally a randomised protocol version parameter
{
"1mpmxz2yun22rwnn":[
"1_32739_21790",
"1_32740_21790",
"1_32741_21790",
"1_32742_21790"
],
"yyngyttbmmbuvdpa":"4467ff9bgxxe4csa",
"avz401t36lzrapis":"c5d0a5d608f729a1232bebdc12fb86ba5fb6c43f",
"nzd23jqm9k1cnnij":12,
"0dod6onpa1s4fezp":-90000000,
"soass3t7mm7anneo":-180000000,
"cvarmr3o00ngylo1":90000000,
"udzwnlx07hzd3bfo":180000000
}

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
[
"28cbec08d88643828755bd56b67fca75.9",
1359639986825,
{
"controllingTeam": {
"team": "RESISTANCE"
},
"creator": {
"creatorGuid": "2b8fb33c8d1b433d9a46da76b35185f8.c",
"creationTime": "1359639986543"
},
"edge": {
"destinationPortalGuid": "9b08215c6da44ba18c948f5b7243dc00.12",
"originPortalLocation": {
"lngE6": 8561013,
"latE6": 49384861
},
"destinationPortalLocation": {
"lngE6": 8562566,
"latE6": 49383951
},
"originPortalGuid": "9e4a0dfacd5347e9ac71910761541699.12"
}
}
],

View File

@ -1,162 +0,0 @@
[
"2c124b4e99074660a72668c888093834.11",
1359563604824,
{
"turret": {
},
"resonatorArray": {
"resonators": [
{
"slot": 0,
"level": 5,
"energyTotal": 2825,
"distanceToPortal": 35,
"id": "26da7ed9-9025-4974-b62f-495750b2d888",
"ownerGuid": "a1dc117457954b99b104be8c85e16276.c"
},
{
"slot": 1,
"level": 6,
"energyTotal": 3725,
"distanceToPortal": 25,
"id": "f7f3312c-7440-4edf-95b9-9e416af1f399",
"ownerGuid": "a1dc117457954b99b104be8c85e16276.c"
},
{
"slot": 2,
"level": 5,
"energyTotal": 2825,
"distanceToPortal": 31,
"id": "50627504-1efb-445d-84b0-f014948aedfb",
"ownerGuid": "c4981119edfb488a9fd19d99eb540449.c"
},
{
"slot": 3,
"level": 6,
"energyTotal": 3725,
"distanceToPortal": 31,
"id": "06ee68fe-80e4-491b-a99d-aa126c9740d6",
"ownerGuid": "ef9657c5cc2743afa5e1953dd06df307.c"
},
{
"slot": 4,
"level": 6,
"energyTotal": 3725,
"distanceToPortal": 30,
"id": "df80cd1f-d347-4dc5-a31b-deb8fb9f978d",
"ownerGuid": "ef9657c5cc2743afa5e1953dd06df307.c"
},
{
"slot": 5,
"level": 5,
"energyTotal": 2825,
"distanceToPortal": 24,
"id": "c8c474ec-8deb-4218-8b7b-ea2a7ea3e4ac",
"ownerGuid": "a0c2e839783f4e889ca570e2cd5c7819.c"
},
{
"slot": 6,
"level": 5,
"energyTotal": 2825,
"distanceToPortal": 29,
"id": "e57ea7b1-f3f7-4a62-a060-c794f85246e1",
"ownerGuid": "a0c2e839783f4e889ca570e2cd5c7819.c"
},
{
"slot": 7,
"level": 5,
"energyTotal": 2825,
"distanceToPortal": 31,
"id": "d08b9027-88f3-4808-bd3f-41acce7e195a",
"ownerGuid": "c4981119edfb488a9fd19d99eb540449.c"
}
]
},
"imageByUrl": {
"imageUrl": "http:\/\/lh3.ggpht.com\/oh3OKN-Vc-GbS3hfp4ZaCB_ND6hmkfnp-gAQmCtfmmrj9R94eeiVAAh9HLd5gO-JV8rBGchle8CXLbr_bmK8sR-PdRYS1yCNHS48wf98RelEVjOe"
},
"controllingTeam": {
"team": "RESISTANCE"
},
"defaultActionRange": {
},
"portalV2": {
"linkedEdges": [
{
"otherPortalGuid": "a38615195c7547639dfb77bfe3a700a8.11",
"edgeGuid": "29c13e7a9ba149008aa6355e201158f1.9",
"isOrigin": false
},
{
"otherPortalGuid": "4dd1ede906a44420aa2b052a1363f170.11",
"edgeGuid": "cecc7c69103d4678aeb7172a1688e2b5.9",
"isOrigin": false
},
{
"otherPortalGuid": "9d1fa3603e8c4363b3cd2448277a906b.11",
"edgeGuid": "ed61e4455e574a1c906778f29307a7b4.9",
"isOrigin": true
},
{
"otherPortalGuid": "20c14bddc1384ee99dfe77c10737e842.11",
"edgeGuid": "0d63bde0620a4a89ad4a23ce8ef29c63.9",
"isOrigin": false
}
],
"linkedModArray": [
{
"installingUser": "a1dc117457954b99b104be8c85e16276.c",
"type": "RES_SHIELD",
"stats": {
"MITIGATION": "8"
},
"displayName": "Portal Shield",
"rarity": "RARE"
},
{
"installingUser": "a1dc117457954b99b104be8c85e16276.c",
"type": "RES_SHIELD",
"stats": {
"MITIGATION": "8"
},
"displayName": "Portal Shield",
"rarity": "RARE"
},
{
"installingUser": "a0c2e839783f4e889ca570e2cd5c7819.c",
"type": "RES_SHIELD",
"stats": {
"MITIGATION": "8"
},
"displayName": "Portal Shield",
"rarity": "RARE"
},
{
"installingUser": "ef9657c5cc2743afa5e1953dd06df307.c",
"type": "RES_SHIELD",
"stats": {
"MITIGATION": "6"
},
"displayName": "Portal Shield",
"rarity": "COMMON"
}
],
"descriptiveText": {
"TITLE": "M\u00f6biusband",
"ADDRESS": "Im Neuenheimer Feld 306, 69120 Heidelberg, Germany"
}
},
"locationE6": {
"lngE6": 8672899,
"latE6": 49417115
},
"captured": {
"capturedTime": "1359390335006",
"capturingPlayerId": "a1dc117457954b99b104be8c85e16276.c"
}
}
]

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @id ingress-intel-total-conversion@jonatkins
// @name IITC: Ingress intel map total conversion
// @version 0.15.1.@@DATETIMEVERSION@@
// @version 0.16.0.@@DATETIMEVERSION@@
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL @@UPDATEURL@@
// @downloadURL @@DOWNLOADURL@@

View File

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cradle.iitc_mobile"
android:installLocation="auto"
android:versionCode="60"
android:versionName="0.9">
android:versionCode="61"
android:versionName="0.10.0">
<uses-sdk
android:minSdkVersion="14"
@ -11,8 +11,10 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@ -26,8 +28,7 @@
android:name=".IITC_Mobile"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/AppBaseTheme">
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@ -78,19 +79,16 @@
<activity
android:name=".IITC_PreferenceActivity"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:label="@string/activity_settings"
android:theme="@style/AppBaseTheme"/>
android:label="@string/activity_settings"/>
<activity
android:name=".IITC_PluginPreferenceActivity"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
android:label="@string/activity_plugins"
android:theme="@style/AppBaseTheme"/>
android:label="@string/activity_plugins"/>
<activity
android:name=".share.ShareActivity"
android:label="@string/activity_share"
android:noHistory="true"
android:parentActivityName=".IITC_Mobile"
android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
android:parentActivityName=".IITC_Mobile">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".IITC_Mobile"/>

View File

@ -40,12 +40,6 @@
android:key="pref_mics"
android:title="@string/pref_misc_cat">
<!-- summary is set in settings fragment -->
<EditTextPreference
android:defaultValue="local"
android:key="pref_iitc_source"
android:title="@string/pref_select_iitc"/>
<PreferenceScreen
android:fragment="com.cradle.iitc_mobile.fragments.PluginsFragment"
android:key="pref_plugins"
@ -85,6 +79,12 @@
android:summary="@string/pref_enable_dev_mode_sum"
android:title="@string/pref_enable_dev_mode"/>
<!-- summary is set in settings fragment -->
<EditTextPreference
android:defaultValue="local"
android:key="pref_iitc_source"
android:title="@string/pref_select_iitc"/>
<PreferenceCategory
android:key="pref_advanced_ui_cat"
android:title="@string/pref_ui_cat">

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;

View File

@ -13,58 +13,46 @@ offers many more features. It is available for
<h3>Latest news</h3>
<h4>11th November 2013</h4>
<h4>2nd December 2013</h3>
<p>
IITC 0.15.0 and IITC Mobile 0.9 have just been released. This update fixes things to work with the latest changes
to the standard intel site. Also
<ul>
<li>Support for Jarvis shards (and other future artifacts)</li>
<li>New base map plugins - for <a href="http://maps.stamen.com/">maps.stamen.com/</a> and Bing maps.</li>
</ul>
IITC 0.16.0 and IITC Mobile 0.10.0 have been released. This update is required to work with the latest changes to
the standard intel site. This update took a fair amount of work due to major changes
in the network protocol used behind the standard intel website, hence the longer than usual delay for the update.
</p>
<p>
As well as IITC itself, nearly every single plugin broke in some way due to these changes. Due to the amount of work
needed to get everything possible working again, some plugins have been disabled for now. You can see the list of these
disabled plugins in the download list - they're in the 'Deleted' category with a description of 'PLUGIN CURRENTLY UNAVAILABLE'.
</p>
<p>
Shortly after the Niantic changes that broke IITC, there were reports of IITC users being banned. This seemed strange at
first, as IITC was not even functioning at this time, so why would people be using it and getting banned. The conclusion
that was reached was that a few people who tried to use the broken IITC Mobile app triggered either a bug in IITC that
caused excessive requests, or triggered some kind of alert in the intel servers. Changes have been made to IITC now
so this unlikely to be an issue again.
</p>
<h4>7th November 2013</h4>
<h4>27th November 2013</h4>
<p>
IITC 0.14.6 and IITC Mobile 0.7.7.2 released. Another change needed to match a minor update to the standard intel site.
</p>
<h4>6th November 2013</h4>
<p>
IITC 0.14.5 and IITC Mobile 0.7.7.1 have been released. This contains a fix to work with the latest intel site updates.
Other than this, it is identical to the 0.14.4/0.7.7 release.
</p>
<h4>29th October 2013</h4>
<p>
IITC 0.14.4 and IITC Mobile 0.7.7 have just been released. A critical update required to work with changes made to the
standard intel site. Changes include
<ul>
<li>Fix to geodesic circle drawing. They were not correctly distorted, leading to incorrect link ranges drawn on the map.</li>
<li>Bookmarks plugin: add layer and highlighter to indicate bookmarked portals</li>
<li>Player tracker plugin: markers fade for older activity, and separate layers for each faction</li>
<li>The 'About IITC' dialog now lists which plugins are installed. This may not work correctly for 3rd party plugins at this time</li>
<li>Mobile:
<ul>
<li>Custom fullscreen preferences</li>
<li>Install to SD Card</li>
<li>Cache move to SD card option (hence the new permissions)</li>
</ul>
</li>
<li>... and, as always, various bugfixes and improvements.</li>
</ul>
IITC and IITC Mobile are currently broken, due to changes made to the standard intel website. This is a major change in how
portal details are sent, with most of the extra data that the standard site didn't use being removed.
</p>
<p>
<b>3RD PARTY PLUGIN AUTHORS</b>: The plugin wrapper code has been modified to pass through the additional version
information. While existing plugins should continue to work, I highly recommend updating the wrapper code in your
scripts to match.
This is not something simple to fix, and will take some time. Also, it severely cripples what IITC can do, as using this
extra data, not displayed by the standard site, was its big feature.
</p>
<h4>16th October 2013</h4>
<p>
IITC 0.14.3 and IITC Mobile 0.7.4 have just been released. This is a critical update required to work with the latest
changes Niantic have made to the standard intel site. Additionally, the draw-tools plugin now snaps points to portals
when creating lines/polygons/markers (was actually in 0.14.2 release), a bugfix relating to IITC not realising who
'you' are, causing some highlighters to break, and a handful of other tweaks/bugfixes.
We will look into what can be done to get it working again, but it will take some time. Many plugins won't be practical
as the data will not be available.
</p>
<p>
More details, and discussion, available in the
<a href="https://plus.google.com/105383756361375410867/posts/E65qngRjR2T">Google+ post</a>.
</p>
<p>
<b>Update</b> I've created a 'dummy' version of the desktop plugin that will, for now, disable IITC if you leave it installed.
This is shown as version 0.15.99. When a fixed build is released, it will be 0.16.something and will update and start working.
Test versions remain, but broken. Please join the Google+ Community where announcements will be made.
</p>
<a class="btn btn-small" href="?page=news">Older news</a>

View File

@ -1,5 +1,47 @@
<h2>News</h2>
<h4>2nd December 2013</h3>
<p>
IITC 0.16.0 and IITC Mobile 0.10.0 have been released. This update is required to work with the latest changes to
the standard intel site. This update took a fair amount of work due to major changes
in the network protocol used behind the standard intel website, hence the longer than usual delay for the update.
</p>
<p>
As well as IITC itself, nearly every single plugin broke in some way due to these changes. Due to the amount of work
needed to get everything possible working again, some plugins have been disabled for now. You can see the list of these
disabled plugins in the download list - they're in the 'Deleted' category with a description of 'PLUGIN CURRENTLY UNAVAILABLE'.
</p>
<p>
Shortly after the Niantic changes that broke IITC, there were reports of IITC users being banned. This seemed strange at
first, as IITC was not even functioning at this time, so why would people be using it and getting banned. The conclusion
that was reached was that a few people who tried to use the broken IITC Mobile app triggered either a bug in IITC that
caused excessive requests, or triggered some kind of alert in the intel servers. Changes have been made to IITC now
so this unlikely to be an issue again.
</p>
<h4>27th November 2013</h4>
<p>
IITC and IITC Mobile are currently broken, due to changes made to the standard intel website. This is a major change in how
portal details are sent, with most of the extra data that the standard site didn't use being removed.
</p>
<p>
This is not something simple to fix, and will take some time. Also, it severely cripples what IITC can do, as using this
extra data, not displayed by the standard site, was it' big feature.
</p>
<p>
We will look into what can be done to get it working again, but it will take some time. Many plugins won't be practical
as the data will not be available.
</p>
<p>
More details, and discussion, available in the
<a href="https://plus.google.com/105383756361375410867/posts/E65qngRjR2T">Google+ post</a>.
</p>
<p>
<b>Update</b> I've created a 'dummy' version of the desktop plugin that will, for now, disable IITC if you leave it installed.
This is shown as version 0.15.99. When a fixed build is released, it will be 0.16.something and will update and start working.
Test versions remain, but broken. Please join the Google+ Community where announcements will be made.
</p>
<h4>11th November 2013</h4>
<p>
IITC 0.15.0 and IITC Mobile 0.9 have just been released. This update fixes things to work with the latest changes