diff --git a/code/munge.js b/code/munge.js index f696cce0..7e886e8a 100644 --- a/code/munge.js +++ b/code/munge.js @@ -12,49 +12,53 @@ ;(function(){ var requestParameterMunges = [ - // obsolete munge sets (they don't have some of the new parameters) deleted + // all old munge sets deleted - there's no sign that any old ones will become active again - // set 10 - 2013-11-27 + // set 11 - 2013-12-06 { '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 + 'dashboard.redeemReward': 'ivshfv9zvyfxyqcd', // REDEEM_REWARD + 'dashboard.sendInviteEmail': '1rsx15vc0m8wwdax', // SEND_INVITE_EMAIL + 'dashboard.sendPlext': 'tods2imd0xcfsug6', // SEND_PLEXT // common parameters - method: 'yyngyttbmmbuvdpa', - version: 'avz401t36lzrapis', - version_parameter: 'c5d0a5d608f729a1232bebdc12fb86ba5fb6c43f', + method: '0wvzluo8av4sk17f', + version: 'paeh4g353xu06kfg', + version_parameter: '4acc1e3230c3fd66be3422c0df8dc637336bbd7c', // GET_THINNED_ENTITIES - quadKeys: '1mpmxz2yun22rwnn', + quadKeys: 'ilgv0w4dlldky1yh', + + // GET_PORTAL_DETAILS + guid: '7o8tzmj6oxz1n5w3', + + // REDEEM_REWARD + passcode: 'passcode', // no munging on this parameter + + // SEND_INVITE_EMAIL + inviteeEmailAddress: 'p4rwszdfovuwfdgp', // GET_PAGINATED_PLEXTS - desiredNumItems: 'nzd23jqm9k1cnnij', - minLatE6: '0dod6onpa1s4fezp', - minLngE6: 'soass3t7mm7anneo', - maxLatE6: 'cvarmr3o00ngylo1', - maxLngE6: 'udzwnlx07hzd3bfo', - minTimestampMs: '9iiiks138gkf8xho', - maxTimestampMs: '94wm0u3sc3sgzq7x', - chatTab: 'tqfj4a3okzn5v5o1', - ascendingTimestampOrder: '5jv1m90sq35u6utq', + desiredNumItems: 'kxsbuvc90l6f40xn', + minLatE6: 'llizye3i5dbapxac', + minLngE6: 'w01zpiba1mn5tsab', + maxLatE6: 'd5phhqzj2tbsq599', + maxLngE6: 'avq5srnvg431aehn', + minTimestampMs: 'mhsav5by25wi4s46', + maxTimestampMs: 'hpu7l8h7eccwytyt', + chatTab: 'q9343nem7hs1v37b', + ascendingTimestampOrder: '7pc5c9ggh03pig1b', // SEND_PLEXT message: '8exta9k7y8huhqmc', - latE6: 'kqek161gza3kjcry', - lngE6: '3dlxsqrjj2vcmhbc', -// chatTab: 'efaznrayv5n3jxs0', //guessed parameter name - only seen munged + latE6: '7ffwyf3zd2yf8xam', + lngE6: 'n7ewiach2v22iy20', +// chatTab: 'q9343nem7hs1v37b', // duplicate from GET_PAGINATED_PLEXTS - // GET_PORTAL_DETAILS - guid: 'seg6ohxgnqf9xu9w', - - // SEND_INVITE_EMAIL - inviteeEmailAddress: '8exta9k7y8huhqmc', }, ]; diff --git a/mobile/res/drawable-hdpi/ic_action_place.png b/mobile/res/drawable-hdpi/ic_action_place.png new file mode 100644 index 00000000..dba994d8 Binary files /dev/null and b/mobile/res/drawable-hdpi/ic_action_place.png differ diff --git a/mobile/res/drawable-hdpi/ic_action_settings.png b/mobile/res/drawable-hdpi/ic_action_settings.png deleted file mode 100644 index f50c2d3a..00000000 Binary files a/mobile/res/drawable-hdpi/ic_action_settings.png and /dev/null differ diff --git a/mobile/res/drawable-mdpi/ic_action_place.png b/mobile/res/drawable-mdpi/ic_action_place.png new file mode 100644 index 00000000..ce055ca6 Binary files /dev/null and b/mobile/res/drawable-mdpi/ic_action_place.png differ diff --git a/mobile/res/drawable-mdpi/ic_action_settings.png b/mobile/res/drawable-mdpi/ic_action_settings.png deleted file mode 100644 index 04f61dea..00000000 Binary files a/mobile/res/drawable-mdpi/ic_action_settings.png and /dev/null differ diff --git a/mobile/res/drawable-xhdpi/ic_action_place.png b/mobile/res/drawable-xhdpi/ic_action_place.png new file mode 100644 index 00000000..49adf813 Binary files /dev/null and b/mobile/res/drawable-xhdpi/ic_action_place.png differ diff --git a/mobile/res/drawable-xhdpi/ic_action_settings.png b/mobile/res/drawable-xhdpi/ic_action_settings.png deleted file mode 100644 index 3f2f394f..00000000 Binary files a/mobile/res/drawable-xhdpi/ic_action_settings.png and /dev/null differ diff --git a/mobile/res/drawable-xxhdpi/ic_action_place.png b/mobile/res/drawable-xxhdpi/ic_action_place.png new file mode 100644 index 00000000..25623c77 Binary files /dev/null and b/mobile/res/drawable-xxhdpi/ic_action_place.png differ diff --git a/mobile/res/drawable-xxhdpi/ic_action_settings.png b/mobile/res/drawable-xxhdpi/ic_action_settings.png deleted file mode 100644 index 6725c082..00000000 Binary files a/mobile/res/drawable-xxhdpi/ic_action_settings.png and /dev/null differ diff --git a/mobile/res/menu/main.xml b/mobile/res/menu/main.xml index 8ddb56e3..63790b3f 100644 --- a/mobile/res/menu/main.xml +++ b/mobile/res/menu/main.xml @@ -19,20 +19,20 @@ android:showAsAction="ifRoom" android:title="@string/layer_chooser"> - - + + diff --git a/mobile/res/values/strings.xml b/mobile/res/values/strings.xml index e6e934f0..8d1ed63c 100644 --- a/mobile/res/values/strings.xml +++ b/mobile/res/values/strings.xml @@ -150,9 +150,9 @@ Copied to clipboard… Do not show again - Map + Locate Share - Browser + Intel Highlighter Base Layer diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java index 3332f442..ea2b4092 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java @@ -324,6 +324,12 @@ public class IITC_Mobile extends Activity implements OnSharedPreferenceChangeLis super.onStop(); } + @Override + protected void onDestroy() { + unregisterReceiver(mBroadcastReceiver); + super.onDestroy(); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java b/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java index c0c0fccf..f00cad8d 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_WebView.java @@ -71,7 +71,15 @@ public class IITC_WebView extends WebView { @Override public void run() { if (isInFullscreen() && (getFullscreenStatus() & (FS_NAVBAR)) != 0) { - setSystemUiVisibility(SYSTEM_UI_FLAG_HIDE_NAVIGATION); + int systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION; + // in immersive mode the user can interact with the app while the navbar is hidden + // this mode is available since KitKat + // you can leave this mode by swiping down from the top of the screen. this does only work + // when the app is in total-fullscreen mode + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && (mFullscreenStatus & FS_SYSBAR) != 0) { + systemUiVisibility |= SYSTEM_UI_FLAG_IMMERSIVE; + } + setSystemUiVisibility(systemUiVisibility); } } }; @@ -165,12 +173,7 @@ public class IITC_WebView extends WebView { public void loadJS(String js) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - evaluateJavascript(js, new ValueCallback() { - @Override - public void onReceiveValue(String value) { - // maybe we want to add stuff here - } - }); + evaluateJavascript(js, null); } else { // if in edit text mode, don't load javascript otherwise the keyboard closes. HitTestResult testResult = getHitTestResult(); @@ -190,20 +193,22 @@ public class IITC_WebView extends WebView { @Override public boolean onTouchEvent(MotionEvent event) { getHandler().removeCallbacks(mNavHider); - getHandler().postDelayed(mNavHider, 2000); + getHandler().postDelayed(mNavHider, 3000); return super.onTouchEvent(event); } @Override public void setSystemUiVisibility(int visibility) { - getHandler().postDelayed(mNavHider, 2000); + if ((visibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { + getHandler().postDelayed(mNavHider, 3000); + } super.setSystemUiVisibility(visibility); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { if (hasWindowFocus) { - getHandler().postDelayed(mNavHider, 2000); + getHandler().postDelayed(mNavHider, 3000); } else { getHandler().removeCallbacks(mNavHider); } @@ -225,7 +230,7 @@ public class IITC_WebView extends WebView { attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; } if ((mFullscreenStatus & FS_NAVBAR) != 0) { - setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + getHandler().post(mNavHider); } if ((mFullscreenStatus & FS_STATUSBAR) != 0) { loadUrl("javascript: $('#updatestatus').hide();"); diff --git a/mobile/src/com/cradle/iitc_mobile/share/IntentListView.java b/mobile/src/com/cradle/iitc_mobile/share/IntentListView.java index fdec0b86..785c1edb 100644 --- a/mobile/src/com/cradle/iitc_mobile/share/IntentListView.java +++ b/mobile/src/com/cradle/iitc_mobile/share/IntentListView.java @@ -9,6 +9,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; @@ -37,6 +38,10 @@ public class IntentListView extends ListView { } private class IntentAdapter extends ArrayAdapter { + + // actually the mdpi pixel size is 48, but this looks ugly...so scale icons down for listView + private static final int MDPI_PX = 36; + private IntentAdapter() { super(IntentListView.this.getContext(), android.R.layout.simple_list_item_1); } @@ -48,11 +53,19 @@ public class IntentListView extends ListView { ActivityInfo info = getItem(position).activityInfo; CharSequence label = info.loadLabel(mPackageManager); + + // get icon and scale it manually to ensure that all have the same size Drawable icon = info.loadIcon(mPackageManager); + DisplayMetrics dm = new DisplayMetrics(); + ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm); + float densityScale = dm.density; + float scaledWidth = MDPI_PX * densityScale; + float scaledHeight = MDPI_PX * densityScale; + icon.setBounds(0,0,Math.round(scaledWidth),Math.round(scaledHeight)); view.setText(label); view.setCompoundDrawablePadding((int) getResources().getDimension(R.dimen.icon_margin)); - view.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); + view.setCompoundDrawables(icon, null, null, null); return view; } diff --git a/mobile/src/com/cradle/iitc_mobile/share/ShareActivity.java b/mobile/src/com/cradle/iitc_mobile/share/ShareActivity.java index 24523eeb..b09e57f9 100644 --- a/mobile/src/com/cradle/iitc_mobile/share/ShareActivity.java +++ b/mobile/src/com/cradle/iitc_mobile/share/ShareActivity.java @@ -81,7 +81,7 @@ public class ShareActivity extends FragmentActivity implements ActionBar.TabList String geoUri = "geo:" + mLl; Intent geoIntent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(geoUri)); intents.add(geoIntent); - addTab(intents, R.string.tab_map, R.drawable.ic_action_map); + addTab(intents, R.string.tab_map, R.drawable.ic_action_place); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getUrl())); addTab(intent, R.string.tab_browser, R.drawable.ic_action_web_site); @@ -122,6 +122,9 @@ public class ShareActivity extends FragmentActivity implements ActionBar.TabList setupShareIntent(intent.getStringExtra("shareString")); } + // show portal name as action bar title, if available + if (mTitle != getString(R.string.app_name)) actionBar.setTitle(mTitle); + mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mFragmentAdapter); diff --git a/plugins/basemap-bing.user.js b/plugins/basemap-bing.user.js index 43d0fea8..52944b49 100644 --- a/plugins/basemap-bing.user.js +++ b/plugins/basemap-bing.user.js @@ -2,7 +2,7 @@ // @id iitc-plugin-bing-maps // @name IITC plugin: Bing maps // @category Map Tiles -// @version 0.1.1.@@DATETIMEVERSION@@ +// @version 0.1.2.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ @@ -23,7 +23,7 @@ window.plugin.mapBing = function() {}; window.plugin.mapBing.setupBingLeaflet = function() { @@INCLUDERAW:external/Bing.js@@ } - + window.plugin.mapBing.setup = function() { window.plugin.mapBing.setupBingLeaflet(); @@ -37,12 +37,35 @@ window.plugin.mapBing.setup = function() { 'AerialWithLabels': "Aerial with labels", }; + // bing maps has an annual usage limit, which will likely be hit in 6 months at this time. + // it seems that the usage is counted on initialising the L.BingLayer, when the metadata is retrieved. + // so, we'll create some dummy layers and add those to the map, then, the first time a layer is added, + // create the L.BingLayer. This will eliminate all usage for users who install but don't use the map, + // and only create usage for the map layers actually selected in use + + var bingMapContainers = []; + for (type in bingTypes) { var name = bingTypes[type]; - var bingMap = new L.BingLayer(bingApiKey, {type: type, maxZoom:20}); - layerChooser.addBaseLayer(bingMap, 'Bing '+name); + + bingMapContainers[type] = new L.LayerGroup(); + layerChooser.addBaseLayer(bingMapContainers[type], 'Bing '+name); } + // now a leaflet event to catch base layer changes and create a L.BingLayer when needed + map.on('baselayerchange', function(e) { + for (type in bingMapContainers) { + if (e.layer == bingMapContainers[type]) { + if (bingMapContainers[type].getLayers().length == 0) { + // dummy layer group is empty - create the bing layer + console.log('basemap-bing: creating '+type+' layer'); + var bingMap = new L.BingLayer (bingApiKey, {type: type, maxZoom:20}); + bingMapContainers[type].addLayer(bingMap); + } + } + } + }); + }; var setup = window.plugin.mapBing.setup; diff --git a/plugins/broken/draw-resonators.user.js b/plugins/broken/draw-resonators.user.js deleted file mode 100644 index 6e7ee025..00000000 --- a/plugins/broken/draw-resonators.user.js +++ /dev/null @@ -1,811 +0,0 @@ -// ==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('Resonators '); -} - -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 = '
' - for(var name in this._dialogEntries) { - html += '
' - + this._dialogEntries[name].getHTML() - + '
'; - } - html += '
'; - 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 = '' - + ''; - 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 = '' - + ''; - 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@@ diff --git a/plugins/draw-resonators.user.js b/plugins/draw-resonators.user.js index f85d3b2f..2aa1b7df 100644 --- a/plugins/draw-resonators.user.js +++ b/plugins/draw-resonators.user.js @@ -1,15 +1,116 @@ // ==UserScript== // @id iitc-plugin-draw-resonators@xelio // @name IITC plugin: Draw resonators -// @category Deleted -// @version 0.4.0.@@DATETIMEVERSION@@ +// @category Layer +// @version 0.4.1.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ -// @description PLUGIN CURRENTLY UNAVAILABLE +// @description [@@BUILDNAME@@-@@BUILDDATE@@] Draw resonators on map for currently selected portal. // @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.RESONATOR_MIN_ZOOM = 16; + +// use own namespace for plugin +window.plugin.drawResonators = function() {}; + +window.plugin.drawResonators.levelLayerGroup = null; + +window.plugin.drawResonators.handledata = function(data) { +window.plugin.drawResonators.levelLayerGroup.clearLayers(); +window.plugin.drawResonators.drawData(data); +} + +window.plugin.drawResonators.drawData = function(portal) { +if(window.map.getZoom() < window.RESONATOR_MIN_ZOOM) return; + var portalDetails = portal.portalDetails; + var portalLatLng = [portalDetails.locationE6.latE6/1E6, portalDetails.locationE6.lngE6/1E6]; + for(var i in portalDetails.resonatorArray.resonators) { + resoData = portalDetails.resonatorArray.resonators[i]; + if(resoData === null) continue; + + var resoLatLng = window.plugin.drawResonators.getResonatorLatLng(resoData.distanceToPortal, resoData.slot, portalLatLng); + + var resoMarker = window.plugin.drawResonators.createResoMarker(resoData, resoLatLng); + var connMarker = window.plugin.drawResonators.createConnMarker(resoData, resoLatLng, portalLatLng); + + window.plugin.drawResonators.levelLayerGroup.addLayer(resoMarker); + window.plugin.drawResonators.levelLayerGroup.addLayer(connMarker); + } +} + +window.plugin.drawResonators.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.createResoMarker = function(resoData, resoLatLng) { + var resoProperty = { + fillColor: COLORS_LVL[resoData.level], + fillOpacity: resoData.energyTotal/RESO_NRG[resoData.level], + color: '#aaa', + weight: 1, + radius: 3, + opacity: 1, + clickable: false}; + resoProperty.type = 'resonator'; + resoProperty.details = resoData; + var reso = L.circleMarker(resoLatLng, resoProperty); + return reso; +} + +window.plugin.drawResonators.createConnMarker = function(resoData, resoLatLng, portalLatLng) { + var connProperty = { + opacity: 0.25, + weight: 2, + color: '#FFA000', + dashArray: '0,10' + (new Array(25).join(',8,4')), + fill: false, + clickable: false}; + connProperty.type = 'connector'; + connProperty.details = resoData; + var conn = L.polyline([portalLatLng, resoLatLng], connProperty); + return conn; +} + +window.plugin.drawResonators.zoomListener = function() { + if(window.map.getZoom() < window.RESONATOR_MIN_ZOOM) { + window.plugin.drawResonators.levelLayerGroup.clearLayers(); + }; +} + +var setup = function() { + + window.plugin.drawResonators.levelLayerGroup = new L.LayerGroup(); + + window.addLayerGroup('Draw Reso', window.plugin.drawResonators.levelLayerGroup, true); + + window.addHook('portalDetailsUpdated', window.plugin.drawResonators.handledata); + + window.map.on('zoomend', function() { + window.plugin.drawResonators.zoomListener(); + }); + +} +// PLUGIN END ////////////////////////////////////////////////////////// + +@@PLUGINEND@@ \ No newline at end of file diff --git a/plugins/guess-player-levels.user.js b/plugins/guess-player-levels.user.js index 920a2295..4e24bbc0 100644 --- a/plugins/guess-player-levels.user.js +++ b/plugins/guess-player-levels.user.js @@ -2,7 +2,7 @@ // @id iitc-plugin-guess-player-levels@breunigs // @name IITC plugin: guess player level // @category Info -// @version 0.5.0.@@DATETIMEVERSION@@ +// @version 0.5.1.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ @@ -119,56 +119,80 @@ window.plugin.guessPlayerLevels.extractPortalData = function(data) { 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 - //has happened, but in many cases it will result in an impossible deployment arrangement - //(over 1 L8/7 res, over 2 L6/5 res, etc). if we detect this case, ignore all resonators owned - //by that player on the portal + /* 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 has happened, but in many cases it will + result in an impossible deployment arrangement (more than 1 L8/7 res, more than 2 L6/5 res, etc). If we detect this + case, we ignore all resonators owned by that player on the portal + Hint: This can only happen to the owner of the portal, so resonators by other players can be used to determine + their minimal level */ -// TODO? go further, and just ignore all resonators owned by the portal owner? -// or; have a 'guessed' level and a 'certain' level. 'certain' comes from res from non-owner, and COMM deploy -// while 'guessed' comes from resonators of the portal owner + var owner = data.details.captured && data.details.captured.capturingPlayerId || ""; + var ownerModCount = 0; + data.details.portalV2.linkedModArray.forEach(function(mod) { + if(mod && mod.installingUser == owner) + ownerModCount++; + }); - var perPlayerResMaxLevel = {}; - var perPlayerResMaxLevelCount = {}; + var players = {}; $.each(r, function(ind, reso) { if(!reso) return true; - if(!perPlayerResMaxLevel[reso.ownerGuid] || reso.level > perPlayerResMaxLevel[reso.ownerGuid]) { - perPlayerResMaxLevel[reso.ownerGuid] = reso.level; - perPlayerResMaxLevelCount[reso.ownerGuid] = 0; - } - if (reso.level == perPlayerResMaxLevel[reso.ownerGuid]) perPlayerResMaxLevelCount[reso.ownerGuid]++; + if(!players[reso.ownerGuid]) players[reso.ownerGuid] = []; + + if(players[reso.ownerGuid][reso.level] === undefined) + players[reso.ownerGuid][reso.level] = 1 + else + players[reso.ownerGuid][reso.level]++; }); - $.each(perPlayerResMaxLevel, function(guid, level) { - if (perPlayerResMaxLevelCount[guid] <= window.MAX_RESO_PER_PLAYER[level]) { - window.plugin.guessPlayerLevels.savePlayerLevel(guid, level); + for(nickname in players) { + var ignore = false; + var minLevel = 0; + + if(nickname == owner) { + if(ownerModCount > 2) // more than 2 mods by capturing player --> portal was flipped, ignore their resonators + continue; + var certain = false; + } else { // not deployed by owner - player must be at least that level + var certain = true; } - }); + + players[nickname].forEach(function(count, level) { + if(MAX_RESO_PER_PLAYER[level] < count) + ignore = true; + + if(count > 0) + minLevel = level; + }); + + if(ignore) + continue; + + window.plugin.guessPlayerLevels.savePlayerLevel(nickname, minLevel, certain); + } } 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); - } - }); + 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) { +window.plugin.guessPlayerLevels.savePlayerLevel = function(nick, level, certain) { var cache = window.plugin.guessPlayerLevels._loadLevels(); var details = cache['#' + nick]; @@ -177,7 +201,7 @@ window.plugin.guessPlayerLevels.savePlayerLevel = function(nick, level, safe) { if(typeof details === 'number') details = {min: 1, guessed: details}; - if(safe) { + if(certain) { if(details.min >= level) return; diff --git a/plugins/pan-control.user.js b/plugins/pan-control.user.js index 69486c55..1e1ca84e 100644 --- a/plugins/pan-control.user.js +++ b/plugins/pan-control.user.js @@ -26,10 +26,16 @@ window.plugin.panControl.setup = function() { try { console.log('Loading Leaflet.Pancontrol JS now'); } catch(e) {} @@INCLUDERAW:external/L.Control.Pan.js@@ try { console.log('done loading Leaflet.Pancontrol JS'); } catch(e) {} - + + // prevent Pancontrol from being activated by default (e.g. in minimap) + L.Map.mergeOptions({ + panControl: false + }); + + window.map.panControl = L.control.pan({panOffset: 350}); window.map.addControl(window.map.panControl); - + if(map.zoomControl._map) { // Move above the zoom control window.map.removeControl(map.zoomControl); window.map.zoomControl = L.control.zoom();