// ==UserScript== // @author Heistergand // @name Fan Fields 2 // @id fanfields@heistergand // @category Layer // @version 2.6.2.20240630 // @description Calculate how to link the portals to create the largest tidy set of nested fields. Enable from the layer chooser. // @downloadURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/heistergand/fanfields.user.js // @updateURL https://raw.githubusercontent.com/IITC-CE/Community-plugins/master/dist/heistergand/fanfields.meta.js // @icon https://raw.githubusercontent.com/Heistergand/fanfields2/master/fanfields2-32.png // @icon64 https://raw.githubusercontent.com/Heistergand/fanfields2/master/fanfields2-64.png // @supportURL https://github.com/Heistergand/fanfields2/issues // @namespace https://github.com/Heistergand/fanfields2 // @issueTracker https://github.com/Heistergand/fanfields2/issues // @homepageURL https://github.com/Heistergand/fanfields2/ // @depends draw-tools@breunigs // @recommends bookmarks@ZasoGD|draw-tools-plus@zaso|liveInventory@DanielOnDiordna|keys@xelio // @preview https://raw.githubusercontent.com/Heistergand/fanfields2/master/FanFields2.png // @match https://intel.ingress.com/* // @include https://intel.ingress.com/* // @grant none // ==/UserScript== /* Version History: -- Version History moved into the code. Todo: Add a kind of system to have a cluster of Fanfields Calculate distance to walk for the plan (crow / streets) Calculate the most efficient possible plan based on ways to walk and keys to farm Export to Tasks Bookmarks saving works, but let it also save into a Bookmarks Folder Calculate amount of possible rebuilds after flippinig the center portal Click on a link to flip it's direction */ function wrapper(plugin_info) { // ensure plugin framework is there, even if iitc is not yet loaded if(typeof window.plugin !== 'function') window.plugin = function() {}; plugin_info.buildName = 'main'; plugin_info.dateTimeVersion = '2024-04-10-233042'; plugin_info.pluginId = 'fanfields'; /* global L -- eslint */ /* exported setup, changelog --eslint */ let arcname = window.PLAYER.team === 'ENLIGHTENED' ? 'Arc' : '***'; var changelog = [ { version: '2.6.2', changes: [ 'NEW: Task list now contains a single navigation link for each portal.', ], }, { version: '2.6.1', changes: [ 'FIX: Counts of outgoing links and sbul are now correct when respecting intel and using outbounding mode.', ], }, { version: '2.6.0', changes: [ 'NEW: Add control buttons for better ux on mobile.', ], }, { version: '2.5.6', changes: [ 'NEW: Implementing link details in show-as-list dialog.', ], }, { version: '2.5.5', changes: [ 'FIX: Plugin did not work on IITC-Mobile.', ], }, { version: '2.5.4', changes: [ 'NEW: Option to only use bookmarked portals within the Fanfields (Toggle-Button)', ], }, { version: '2.5.3', changes: [ 'NEW: Saving to Bookmarks now creates a folder in the Bookmarks list.', ], }, { version: '2.5.2', changes: [ 'FIX: Prefer LiveInventory Plugin over Keys Plugin (hotfix)', ], }, { version: '2.5.1', changes: [ 'FIX: Prefer LiveInventory Plugin over Keys Plugin', ], }, { version: '2.5.0', changes: [ 'NEW: Integrate key counts from LiveInventory plugin.', ], }, { version: '2.4.1', changes: [ 'FIX: "Show as List" without having the Keys Plugin did not show any Keys.', ], }, { version: '2.4.0', changes: [ 'NEW: Integrate functionality with Key Plugin.', 'NEW: Replace fieldset box design with a separated sidebar box.', ], }, { version: '2.3.2', changes: [ 'NEW: Introducing code for upcoming multiple fanfields by Drawtools Colors', 'FIX: some code refactorings', 'FIX: SBUL defaults to 2 now, assuming most fields are done solo.', 'FIX: If a marker is not actually snapped onto a portal it does not act as fan point anymore.', 'FIX: When adding a marker, it\'s now selected as start portal.', ], }, { version: '2.3.1', changes: [ 'FIX: Portals were difficult to select underneath the fanfileds plan.', ], }, { version: '2.3.0', changes: [ 'NEW: Added '+arcname+' support.', ], }, { version: '2.2.9', changes: [ 'FIX: Link direction indicator did not work anymore.', 'NEW: Link direction indicator is now optional.', 'NEW: New plugin icon showing a hand fan.', ], }, { version: '2.2.8', changes: [ 'FIX: minor changes', ], }, { version: '2.2.7', changes: [ 'FIX: Menue Buttons in Mobile version are now actually buttons.', ], }, { version: '2.2.6', changes: [ 'NEW: Google Maps Portal Routing', ], }, { version: '2.2.5', changes: [ 'NEW: Set how many SBUL you plan to use.', 'FIX: Anchor shift button design changed', ], }, { version: '2.2.4', changes: [ 'FIX: Fixed what should have been fixed in 2.2.4', ], }, { version: '2.2.4', changes: [ 'FIX: Width of dialog boxes did extend screen size', ], }, { version: '2.2.3', changes: [ 'FIX: Made Bookmark Plugin optional', 'NEW: Anchor shifting ("Cycle Start") is now bidirectional.', 'FIX: Some minor fixes and code formatting.', ], }, { version: '2.2.2', changes: [ 'NEW: Added favicon.ico to script header.', ], }, { version: '2.2.1', changes: [ 'FIX: Merged from Jormund fork (2.1.7): Fixed L.LatLng extension', ], }, { version: '2.2.0', changes: [ 'FIX: Reintroducing the marker function which was removed in 2.1.7 so that a Drawtools Marker can be used to force a portal inside (or outside) the hull to be the anchor.', ], }, { version: '2.1.10', changes: [ 'FIX: minor fixes', ], }, { version: '2.1.9', changes: [ 'FIX: minor fixes', ], }, { version: '2.1.9', changes: [ 'FIX: Fixed blank in header for compatibility with IITC-CE Button.', ], }, { version: '2.1.9', changes: [ 'FIX: Fix for missing constants in leaflet verion 1.6.0.', ], }, { version: '2.1.8', changes: [ 'NEW: Added starting portal advance button to select among the list of perimeter portals.', ], }, { version: '2.1.7', changes: [ 'DEL: Removed marker and random selection of starting point portal.', 'NEW: Replaced with use of first outer hull portal. This ensures maximum fields will be generated.', ], }, { version: '2.1.5', changes: [ 'FIX: Minor syntax issue affecting potentially more strict runtimes', ], }, { version: '2.1.4', changes: [ 'FIX: Make the clockwise button change its label to "Counterclockwise" when toggled', ], }, { version: '2.1.3', changes: [ 'FIX: added id tags to menu button elements, ...just because.', ], }, { version: '2.1.2', changes: [ 'FIX: Minor issues', ], }, { version: '2.1.1', changes: [ 'FIX: changed List export format to display as a table', ], }, { version: '2.1.0', changes: [ 'NEW: Added save to DrawTools functionality', 'NEW: Added fanfield statistics', 'FIX: Changed some menu texts', 'VER: Increased Minor Version due to DrawTools Milestone', ], }, { version: '2.0.9', changes: [ 'NEW: Added the number of outgoing links to the simple list export', ], }, { version: '2.0.8', changes: [ 'NEW: Toggle the direction of the star-links (Inbound/Outbound) and calculate number of SBUL', 'FIX: Despite crosslinks, respecting the current intel did not handle done links', ], }, { version: '2.0.7', changes: [ 'FIX: Sorting of the portals was not accurate for far distance anchors when the angle was too equal.', 'NEW: Added option to respect current intel and not crossing lines.', ], }, { version: '2.0.6', changes: [ 'FIX: Plan messed up on multiple polygons.', ], }, { version: '2.0.5', changes: [ 'FIX: fan links abandoned when Marker was outside the polygon', 'BUG: Issue found where plan messes up when using more than one polygon (fixed in 2.0.6)', ], }, { version: '2.0.4', changes: [ 'NEW: Added Lock/Unlock button to freeze the plan and prevent recalculation on any events.', 'NEW: Added a simple text export (in a dialog box)', 'FIX: Several changes to the algorithm', 'BUG: Issue found where links are closing fields on top of portals that are successors in the list once you got around the startportal', ], }, { version: '2.0.3', changes: [ 'FIX: Counterclockwise did not work properly', 'NEW: Save as Bookmarks', ], }, { version: '2.0.2', changes: [ 'NEW: Added Menu', 'NEW: Added counterclockwise option', 'FIX: Minor Bugfixes', ], }, { version: '2.0.1', changes: [ 'NEW: Count keys to farm', 'NEW: Count total fields', 'NEW: Added labels to portals', 'FIX: Links were drawn in random order', 'FIX: Only fields to the center portal were drawn', ], }, ]; // PLUGIN START //////////////////////////////////////////////////////// // use own namespace for plugin /* jshint shadow:true */ window.plugin.fanfields = function() {}; var thisplugin = window.plugin.fanfields; // const values // zoom level used for projecting points between latLng and pixel coordinates. may affect precision of triangulation thisplugin.PROJECT_ZOOM = 16; thisplugin.LABEL_WIDTH = 100; thisplugin.LABEL_HEIGHT = 49; // constants no longer present in leaflet 1.6.0 thisplugin.DEG_TO_RAD = Math.PI / 180; thisplugin.RAD_TO_DEG = 180 / Math.PI; thisplugin.labelLayers = {}; thisplugin.startingpoint = undefined; thisplugin.availableSBUL = 2; thisplugin.locations = []; thisplugin.fanpoints = []; thisplugin.sortedFanpoints = []; thisplugin.perimeterpoints = []; thisplugin.startingpointIndex = 0; thisplugin.links = []; thisplugin.linksLayerGroup = null; thisplugin.fieldsLayerGroup = null; thisplugin.numbersLayerGroup = null; thisplugin.selectPolygon = function() {}; thisplugin.saveBookmarks = function() { // loop thru portals and UN-Select them for bkmrks var bkmrkData, list; thisplugin.sortedFanpoints.forEach(function(point, index) { bkmrkData = window.plugin.bookmarks.findByGuid(point.guid); if(bkmrkData) { list = window.plugin.bookmarks.bkmrksObj.portals; delete list[bkmrkData.id_folder].bkmrk[bkmrkData.id_bookmark]; $('.bkmrk#'+bkmrkData.id_bookmark + '').remove(); window.plugin.bookmarks.saveStorage(); window.plugin.bookmarks.updateStarPortal(); window.runHooks('pluginBkmrksEdit', {"target": "portal", "action": "remove", "folder": bkmrkData.id_folder, "id": bkmrkData.id_bookmark, "guid":point.guid}); console.log('Fanfields2: removed BOOKMARKS portal ('+bkmrkData.id_bookmark+' situated in '+bkmrkData.id_folder+' folder)'); } }); let type = "folder"; let label = 'Fanfields2'; // Add new folder in the localStorage let folder_ID = window.plugin.bookmarks.generateID(); window.plugin.bookmarks.bkmrksObj.portals[folder_ID] = {"label":label,"state":1,"bkmrk":{}}; window.plugin.bookmarks.saveStorage(); window.plugin.bookmarks.refreshBkmrks(); window.runHooks('pluginBkmrksEdit', {"target": type, "action": "add", "id": folder_ID}); console.log('Fanfields2: added BOOKMARKS '+type+' '+folder_ID); thisplugin.addPortalBookmark = function(guid, latlng, label, folder_ID) { var bookmark_ID = window.plugin.bookmarks.generateID(); // Add bookmark in the localStorage window.plugin.bookmarks.bkmrksObj.portals[folder_ID].bkmrk[bookmark_ID] = {"guid":guid,"latlng":latlng,"label":label}; window.plugin.bookmarks.saveStorage(); window.plugin.bookmarks.refreshBkmrks(); window.runHooks('pluginBkmrksEdit', {"target": "portal", "action": "add", "id": bookmark_ID, "guid": guid}); console.log('Fanfields2: added BOOKMARKS portal '+bookmark_ID); } // loop again: ordered(!) to add them as bookmarks thisplugin.sortedFanpoints.forEach(function(point, index) { if (point.guid) { var p = window.portals[point.guid]; var ll = p.getLatLng(); //plugin.bookmarks.addPortalBookmark(point.guid, ll.lat+','+ll.lng, p.options.data.title); thisplugin.addPortalBookmark(point.guid, ll.lat+','+ll.lng, p.options.data.title, folder_ID) } }); }; thisplugin.updateStartingPoint = function(i) { thisplugin.startingpointIndex = i; thisplugin.startingpointGUID = thisplugin.perimeterpoints[thisplugin.startingpointIndex][0]; thisplugin.startingpoint = this.fanpoints[thisplugin.startingpointGUID]; thisplugin.updateLayer(); } // cycle to next starting point on the convex hull list of portals thisplugin.nextStartingPoint = function() { // *** startingpoint handling is duplicated in updateLayer(). var i = thisplugin.startingpointIndex + 1; if (i >= thisplugin.perimeterpoints.length) { i = 0; } thisplugin.updateStartingPoint(i); }; thisplugin.previousStartingPoint = function() { var i = thisplugin.startingpointIndex - 1; if (i < 0) { i = thisplugin.perimeterpoints.length -1; } thisplugin.updateStartingPoint(i); }; thisplugin.generateTasks = function() {}; thisplugin.reset = function() {}; thisplugin.helpDialogWidth = 650; thisplugin.help = function() { var width = thisplugin.helpDialogWidth; if (thisplugin.MaxDialogWidth < thisplugin.helpDialogWidth) { width = thisplugin.MaxDialogWidth; } dialog({ html: '
Using Drawtools, draw one or more polygons around the portals you want to work with. '+ 'The Polygons can overlap each other or be completely seperated. All portals within the polygons '+ 'count to your planned fanfield.
'+ 'From the layer selector, enable the 3 Fanfields layer for links, fields and numbers. '+ 'The fanfield will be calculated and shown in red links on the intel. Link directions are indicated '+ 'by dashed links at the portal to lnk from.
'+ 'The script selects an anchor portal from the hull of all selected portals. Use the Cycle Start '+ 'Button to select another hull portal as anchor.
'+ 'If you want to use portal as anchor, which is inside the hull, (which is totally legitimate), '+ 'place a marker on a portal to enforce it to be a possible anchor. Again, use the Cycle Start '+ 'Button until the Start Portal is where you want it to be.
'+ 'A Fanfield can be done inbounding by farming many keys at a portal and then link to it by all '+ 'the other portals. It can also be done outbounding by star-linking from the start portal until the maximum '+ 'number of outgoing links is reached. You can toggle that for planning accordingly.
'+ 'You might need to plan your field around links you cannot or do not want to destroy. This is where the '+ 'Respect Intel button comes into play. Toggle this to plan your fanfield avoiding crosslinks.
'+ 'Use the Lock function to prevent the script from recalculating anything. This is useful '+ 'if you have a large area and want to zoom into details.
'+ 'Try to switch your plan to counterclockwise direction. Your route might be easier or harder '+ 'if you change directions. Also try different anchors to get one more field out of some portal '+ 'constellations.
'+ 'Copy your fanfield portals to bookmarks or drawtools to extend your possibilites to work '+ 'with the information.
'+ 'Found a bug? Post your issues at GitHub:
https://github.com/Heistergand/fanfields2/issues
FanPortals: | " + (thisplugin.n-1) + " |
CenterKeys: | " + thisplugin.centerKeys +" |
Total links / keys: | " + thisplugin.donelinks.length.toString() +" |
Fields: | " + thisplugin.triangles.length.toString() +" |
Build AP (links and fields): | " + (thisplugin.donelinks.length*313 + thisplugin.triangles.length*1250).toString() +" |
Destroy AP (links and fields): | " + (thisplugin.sortedFanpoints.length*187 + thisplugin.triangles.length*750).toString() + " |
Pos. | "; text+="Action | "; text+="Portal Name | "; text+="Keys | "; text+="Links | "; text+="||
---|---|---|---|---|---|---|
' + (index) + ' | '; // Action text+=''; text+=' '; text+=' '; text+=' | '; // Portal Name // text+=''+ title + ' | '; let uriTitle=encodeURIComponent(title); text+=''; text+=` ${title}`; text+=' | '; // Keys text+=''; // Links text+=' | ' + portal.outgoing.length + ' | '; // other //text+=''; //text+=''; //text+=' | '; // Row End text+='
' + (index) + '.' + thisplugin.sortedFanpoints.indexOf(outPortal) + ' | '; // Action linkDetailText+=''; linkDetailText+='Link to ' + thisplugin.sortedFanpoints.indexOf(outPortal); linkDetailText+=' | '; let outPortalTitle = 'unknown title'; if (outPortal.portal !== undefined) { outPortalTitle = outPortal.portal.options.data.title; } // Portal Name linkDetailText+=''+ outPortalTitle + ' | '; // Distance linkDetailText+='' + formatDistance(distance) + ' | '; // Links // linkDetailText+='' + portal.outgoing.length + ' | '; // other //linkDetailText+=''; //linkDetailText+=''; //linkDetailText+=' | '; // Row End linkDetailText+='