├── config.json.template ├── requirements.txt ├── Map_Screenshot.png ├── static ├── font │ ├── icomoon.eot │ ├── icomoon.ttf │ ├── icomoon.woff │ └── icomoon.svg ├── resources │ ├── alpha.png │ ├── player.png │ ├── pokeball.png │ ├── pokemon.png │ ├── alpha-green.png │ ├── alpha-grey.png │ ├── pokeball-grey.png │ ├── pokeball-green.png │ ├── text_natures.txt │ └── text_species.txt ├── sidebar-v2 │ ├── doc │ │ ├── ol2-1.png │ │ ├── ol2-2.png │ │ ├── ol3-1.png │ │ ├── ol3-2.png │ │ ├── gmaps-1.png │ │ ├── gmaps-2.png │ │ ├── leaflet-1.png │ │ ├── leaflet-2.png │ │ └── sidebar-v2.gif │ ├── .gitignore │ ├── .travis.yml │ ├── typescript │ │ └── leaflet-sidebar.d.ts │ ├── bower.json │ ├── js │ │ ├── jquery-sidebar.min.js │ │ ├── ol3-sidebar.min.js │ │ ├── jquery-sidebar.js │ │ ├── leaflet-sidebar.min.js │ │ ├── ol3-sidebar.js │ │ └── leaflet-sidebar.js │ ├── package.json │ ├── LICENSE │ ├── scss │ │ ├── _ol-base.scss │ │ ├── leaflet-sidebar.scss │ │ ├── ol3-sidebar.scss │ │ ├── ol2-sidebar.scss │ │ ├── gmaps-sidebar.scss │ │ └── _base.scss │ ├── README.md │ ├── CHANGELOG.md │ ├── gulpfile.js │ ├── css │ │ ├── leaflet-sidebar.min.css │ │ ├── gmaps-sidebar.min.css │ │ ├── ol3-sidebar.min.css │ │ ├── ol2-sidebar.min.css │ │ ├── leaflet-sidebar.css │ │ ├── gmaps-sidebar.css │ │ ├── ol3-sidebar.css │ │ └── ol2-sidebar.css │ └── examples │ │ ├── gmaps.html │ │ ├── ol2.html │ │ ├── index.html │ │ ├── position-right.html │ │ └── ol3.html ├── js │ └── universal.js └── css │ └── universal.css ├── templates └── index.html ├── xoroshiro.py ├── .gitignore ├── README.md ├── nxreader.py ├── pa8.py └── main.py /config.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "IP": "192.168.0.197" 3 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.2 2 | requests==2.26.0 3 | -------------------------------------------------------------------------------- /Map_Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/Map_Screenshot.png -------------------------------------------------------------------------------- /static/font/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/font/icomoon.eot -------------------------------------------------------------------------------- /static/font/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/font/icomoon.ttf -------------------------------------------------------------------------------- /static/font/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/font/icomoon.woff -------------------------------------------------------------------------------- /static/resources/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/alpha.png -------------------------------------------------------------------------------- /static/resources/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/player.png -------------------------------------------------------------------------------- /static/resources/pokeball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/pokeball.png -------------------------------------------------------------------------------- /static/resources/pokemon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/pokemon.png -------------------------------------------------------------------------------- /static/resources/alpha-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/alpha-green.png -------------------------------------------------------------------------------- /static/resources/alpha-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/alpha-grey.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/ol2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/ol2-1.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/ol2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/ol2-2.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/ol3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/ol3-1.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/ol3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/ol3-2.png -------------------------------------------------------------------------------- /static/resources/pokeball-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/pokeball-grey.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/gmaps-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/gmaps-1.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/gmaps-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/gmaps-2.png -------------------------------------------------------------------------------- /static/resources/pokeball-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/resources/pokeball-green.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/leaflet-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/leaflet-1.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/leaflet-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/leaflet-2.png -------------------------------------------------------------------------------- /static/sidebar-v2/doc/sidebar-v2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lincoln-lm/PLA-Live-Map/HEAD/static/sidebar-v2/doc/sidebar-v2.gif -------------------------------------------------------------------------------- /static/sidebar-v2/.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | 17 | dist 18 | build -------------------------------------------------------------------------------- /static/resources/text_natures.txt: -------------------------------------------------------------------------------- 1 | Hardy 2 | Lonely 3 | Brave 4 | Adamant 5 | Naughty 6 | Bold 7 | Docile 8 | Relaxed 9 | Impish 10 | Lax 11 | Timid 12 | Hasty 13 | Serious 14 | Jolly 15 | Naive 16 | Modest 17 | Mild 18 | Quiet 19 | Bashful 20 | Rash 21 | Calm 22 | Gentle 23 | Sassy 24 | Careful 25 | Quirky -------------------------------------------------------------------------------- /static/sidebar-v2/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | 4 | sudo: false 5 | 6 | cache: 7 | yarn: true 8 | 9 | before_install: 10 | - curl -o- -L https://yarnpkg.com/install.sh | bash 11 | - export PATH=$HOME/.yarn/bin:$PATH 12 | 13 | install: 14 | - yarn install --no-lockfile 15 | 16 | script: 17 | - yarn test 18 | -------------------------------------------------------------------------------- /static/js/universal.js: -------------------------------------------------------------------------------- 1 | var map = L.map("map", { 2 | minZoom: 0, 3 | maxZoom: 2, 4 | crs: L.CRS.Simple, 5 | }).setView([ 0, 0 ], 1); //setView([lat, long], default zoom level) 6 | var southWest = map.unproject([0, 2048], map.getMaxZoom()); 7 | var northEast = map.unproject([2048, 0], map.getMaxZoom()); 8 | map.setMaxBounds(new L.LatLngBounds(southWest, northEast)); -------------------------------------------------------------------------------- /static/sidebar-v2/typescript/leaflet-sidebar.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare namespace L { 4 | 5 | namespace Control { 6 | 7 | interface SidebarOptions { 8 | position: string; 9 | } 10 | 11 | class Sidebar extends Control { 12 | constructor(id: string, options?: SidebarOptions); 13 | options: Control.ControlOptions; 14 | addTo(map: L.Map): this; 15 | remove(map: L.Map): this; 16 | open(id: string): this; 17 | close(): this; 18 | } 19 | 20 | } 21 | 22 | namespace control { 23 | function sidebar(id: string, options?: Control.SidebarOptions): L.Control.Sidebar; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /static/sidebar-v2/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sidebar-v2", 3 | "version": "0.3.1", 4 | "homepage": "https://github.com/Turbo87/sidebar-v2", 5 | "authors": [ 6 | "Tobias Bieniek " 7 | ], 8 | "description": "A responsive sidebar for mapping libraries like Leaflet or OpenLayers", 9 | "main": [ 10 | "css/gmaps-sidebar.css", 11 | "css/leaflet-sidebar.css", 12 | "css/ol2-sidebar.css", 13 | "css/ol3-sidebar.css", 14 | "js/jquery-sidebar.js", 15 | "js/leaflet-sidebar.js", 16 | "js/ol3-sidebar.js" 17 | ], 18 | "keywords": [ 19 | "gis", 20 | "leaflet", 21 | "openlayers", 22 | "map" 23 | ], 24 | "license": "MIT", 25 | "ignore": [ 26 | "doc", 27 | "examples", 28 | ".gitignore" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /static/sidebar-v2/js/jquery-sidebar.min.js: -------------------------------------------------------------------------------- 1 | $.fn.sidebar=function(e){var s=this,i=s.find("ul.sidebar-tabs, .sidebar-tabs > ul"),a=s.children(".sidebar-content").first();return e=$.extend({position:"left"},e||{}),s.addClass("sidebar-"+e.position),i.children("li").children('a[href^="#"]').on("click",function(e){e.preventDefault();var i=$(this).closest("li");i.hasClass("active")?s.close():i.hasClass("disabled")||s.open(this.hash.slice(1),i)}),s.find(".sidebar-close").on("click",function(){s.close()}),s.open=function(e,l){void 0===l&&(l=i.find('li > a[href="#'+e+'"]').parent()),a.children(".sidebar-pane.active").removeClass("active"),a.children("#"+e).addClass("active"),i.children("li.active").removeClass("active"),l.addClass("active"),s.trigger("content",{id:e}),s.hasClass("collapsed")&&(s.trigger("opening"),s.removeClass("collapsed"))},s.close=function(){i.children("li.active").removeClass("active"),s.hasClass("collapsed")||(s.trigger("closing"),s.addClass("collapsed"))},s}; -------------------------------------------------------------------------------- /static/sidebar-v2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sidebar-v2", 3 | "version": "0.4.0", 4 | "description": "A responsive sidebar for mapping libraries like Leaflet or OpenLayers", 5 | "keywords": [ 6 | "gis", 7 | "leaflet", 8 | "map", 9 | "openlayers" 10 | ], 11 | "homepage": "https://github.com/turbo87/sidebar-v2", 12 | "bugs": "https://github.com/turbo87/sidebar-v2/issues", 13 | "license": "MIT", 14 | "author": "Tobias Bieniek ", 15 | "files": [ 16 | "css", 17 | "js", 18 | "scss" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/turbo87/sidebar-v2.git" 23 | }, 24 | "scripts": { 25 | "test": "gulp lint" 26 | }, 27 | "devDependencies": { 28 | "gulp": "~3.9.1", 29 | "gulp-clean": "~0.3.1", 30 | "gulp-concat": "~2.6.1", 31 | "gulp-csslint": "~1.0.0", 32 | "gulp-jshint": "~2.0.4", 33 | "gulp-minify-css": "~1.2.4", 34 | "gulp-rename": "~1.2.0", 35 | "gulp-sass": "^3.1.0", 36 | "gulp-uglify": "~3.0.0", 37 | "gulp-zip": "~4.0.0", 38 | "jshint": "^2.9.5" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /static/sidebar-v2/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Tobias Bieniek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/css/universal.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src: url('../font/icomoon.eot?2h6rwh'); 4 | src: url('../font/icomoon.eot?2h6rwh#iefix') format('embedded-opentype'), 5 | url('../font/icomoon.ttf?2h6rwh') format('truetype'), 6 | url('../font/icomoon.woff?2h6rwh') format('woff'), 7 | url('../font/icomoon.svg?2h6rwh#icomoon') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | [class^="icon-"], [class*=" icon-"] { 14 | /* use !important to prevent issues with browser extensions that change fonts */ 15 | font-family: 'icomoon' !important; 16 | speak: never; 17 | font-style: normal; 18 | font-weight: normal; 19 | font-variant: normal; 20 | text-transform: none; 21 | line-height: 1; 22 | 23 | /* Better Font Rendering =========== */ 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | } 27 | 28 | .icon-pokeball:before { 29 | content: "\e900"; 30 | } 31 | 32 | body { 33 | padding: 0; 34 | margin: 0; 35 | } 36 | html, body, #map { 37 | height: 100%; 38 | width: 100vw; 39 | } -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | Select Map 14 | 15 | 16 | 21 |
22 | 30 |
31 | 32 | -------------------------------------------------------------------------------- /static/sidebar-v2/scss/_ol-base.scss: -------------------------------------------------------------------------------- 1 | $sidebar-bg: rgba(255, 255, 255, 0.4) !default; 2 | $sidebar-border-width: 3px !default; 3 | $sidebar-border-radius: 4px !default; 4 | $sidebar-border: $sidebar-border-width solid transparent !default; 5 | 6 | $tab-fg: #fff !default; 7 | $tabs-bg: rgba(0, 60, 136, 0.5) !default; 8 | $tab-hover-fg: #fff !default; 9 | $tab-hover-bg: rgba(0, 60, 136, 0.6) !default; 10 | $tab-active-fg: #fff !default; 11 | $tab-active-bg: #0074d9 !default; 12 | 13 | $move-map-in-xs: false !default; 14 | 15 | @import 'base'; 16 | 17 | .sidebar { 18 | background-color: $sidebar-bg; 19 | 20 | @media(min-width:$threshold-sm) { 21 | border: $sidebar-border; 22 | border-radius: $sidebar-border-radius; 23 | } 24 | } 25 | 26 | .sidebar-left { 27 | border-right: $sidebar-border; 28 | } 29 | 30 | .sidebar-right { 31 | border-left: $sidebar-border; 32 | } 33 | 34 | .sidebar-tabs { 35 | overflow: hidden; 36 | 37 | @media(min-width:$threshold-sm) { 38 | border-radius: $sidebar-inner-border-radius 0 0 $sidebar-inner-border-radius; 39 | 40 | .collapsed & { 41 | border-radius: $sidebar-inner-border-radius; 42 | } 43 | } 44 | } 45 | 46 | .sidebar-content { 47 | @media(min-width:$threshold-sm) { 48 | border-radius: 0 $sidebar-inner-border-radius $sidebar-inner-border-radius 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /static/sidebar-v2/README.md: -------------------------------------------------------------------------------- 1 | # sidebar-v2 2 | 3 | A responsive sidebar for mapping libraries like [Leaflet](#leaflet) or [OpenLayers](#openlayers-3). 4 | 5 | It is more or less a successor of the [leaflet-sidebar](https://github.com/turbo87/leaflet-sidebar/) plugin, thus the `v2` suffix. 6 | 7 | Flattr this 8 | 9 | ![Demo](doc/sidebar-v2.gif) 10 | 11 | 12 | ## [Leaflet](http://leafletjs.com/) 13 | 14 | ![Sidebar collapsed](doc/leaflet-1.png) ![Sidebar extended](doc/leaflet-2.png) 15 | 16 | Example code at [`examples/index.html`](examples/index.html) ([Preview](http://turbo87.github.io/sidebar-v2/examples/index.html)) 17 | 18 | 19 | ## [OpenLayers 3](http://openlayers.org/) 20 | 21 | ![Sidebar collapsed](doc/ol3-1.png) ![Sidebar extended](doc/ol3-2.png) 22 | 23 | Example code at [`examples/ol3.html`](examples/ol3.html) ([Preview](http://turbo87.github.io/sidebar-v2/examples/ol3.html)) 24 | 25 | 26 | ## [OpenLayers 2](http://openlayers.org/two/) 27 | 28 | ![Sidebar collapsed](doc/ol2-1.png) ![Sidebar extended](doc/ol2-2.png) 29 | 30 | Example code at [`examples/ol2.html`](examples/ol2.html) ([Preview](http://turbo87.github.io/sidebar-v2/examples/ol2.html)) 31 | 32 | 33 | ## [Google Maps](https://developers.google.com/maps/) 34 | 35 | ![Sidebar collapsed](doc/gmaps-1.png) ![Sidebar extended](doc/gmaps-2.png) 36 | 37 | Example code at [`examples/gmaps.html`](examples/gmaps.html) ([Preview](http://turbo87.github.io/sidebar-v2/examples/gmaps.html)) 38 | 39 | 40 | ## License 41 | 42 | sidebar-v2 is free software, and may be redistributed under the [MIT license](LICENSE). 43 | -------------------------------------------------------------------------------- /static/font/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static/sidebar-v2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.4.0 (2017-10-25) 4 | 5 | - ol3 version without jquery dependency ([#97](https://github.com/Turbo87/sidebar-v2/pull/97)) 6 | - Allow non-tab links in the sidebar 7 | - add type definition for leaflet-sidebar ([#112](https://github.com/Turbo87/sidebar-v2/pull/112)) 8 | - Remove reference to L.Mixin.Evented ([#124](https://github.com/Turbo87/sidebar-v2/pull/124)) 9 | - Fix Chrome 62 list-style-type bug ([#127](https://github.com/Turbo87/sidebar-v2/pull/127)) 10 | 11 | ## v0.3.1 (2016-11-01) 12 | 13 | - fix `ol3` example map layer ([#77](https://github.com/Turbo87/sidebar-v2/pull/77)) 14 | - leaflet: deprecate `removeFrom()` in favor of `remove()` ([#73](https://github.com/Turbo87/sidebar-v2/pull/73)) 15 | - leaflet: allow non-tab links on the sidebar ([#87](https://github.com/Turbo87/sidebar-v2/pull/87)) 16 | - leaflet: fix CDN location on example pages ([#94](https://github.com/Turbo87/sidebar-v2/pull/94)) 17 | - ol3: move "scale-line" together with the zoom controls ([#93](https://github.com/Turbo87/sidebar-v2/pull/93)) 18 | 19 | ## v0.3.0 (2016-01-19) 20 | 21 | - ol2: move scale line control too when sidebar opens/closes 22 | - hide scrollbars when collapsed ([#21](https://github.com/Turbo87/sidebar-v2/issues/21)) 23 | - fix tab clicking on devices with touch screen *and* mouse ([#34](https://github.com/Turbo87/sidebar-v2/issues/35)) 24 | - new `.sidebar-header` CSS class for styled headings 25 | - new `.sidebar-close` CSS class for close buttons in headings 26 | - fix broken Google Maps code (until Google changes things again...) 27 | - allow `.disabled` on `
  • ` elements in `.sidebar-tabs` element 28 | - allow second tabbar at the bottom 29 | - new `position: 'right'` option 30 | 31 | 32 | ## v0.2.1 (2014-09-29) 33 | 34 | - ol2, ol3: fixed sidebar content scrolling 35 | 36 | 37 | ## v0.2.0 (2014-09-29) 38 | 39 | - jQuery API and events 40 | 41 | 42 | ## v0.1.0 (2014-09-12) 43 | 44 | - first beta release 45 | -------------------------------------------------------------------------------- /static/sidebar-v2/js/ol3-sidebar.min.js: -------------------------------------------------------------------------------- 1 | ol.control.Sidebar=function(t){var s,e;for(this._options=Object.assign({},{element:null,position:"left"},t),ol.control.Control.call(this,{element:document.getElementById(this._options.element),target:this._options.target}),this.element.classList.add("sidebar-"+this._options.position),s=this.element.children.length-1;s>=0;s--)"DIV"===(e=this.element.children[s]).tagName&&e.classList.contains("sidebar-content")&&(this._container=e);for(this._tabitems=this.element.querySelectorAll("ul.sidebar-tabs > li, .sidebar-tabs > ul > li"),s=this._tabitems.length-1;s>=0;s--)this._tabitems[s]._sidebar=this;for(this._panes=[],this._closeButtons=[],s=this._container.children.length-1;s>=0;s--)if("DIV"==(e=this._container.children[s]).tagName&&e.classList.contains("sidebar-pane")){this._panes.push(e);for(var i=e.querySelectorAll(".sidebar-close"),o=0,l=i.length;o=0;s--){var i=(e=this._tabitems[s]).querySelector("a");i.hasAttribute("href")&&"#"==i.getAttribute("href").slice(0,1)&&(i.onclick=this._onClick.bind(e))}for(s=this._closeButtons.length-1;s>=0;s--)(e=this._closeButtons[s]).onclick=this._onCloseClick.bind(this)},ol.control.Sidebar.prototype.open=function(t){var s,e;for(s=this._panes.length-1;s>=0;s--)(e=this._panes[s]).id==t?e.classList.add("active"):e.classList.contains("active")&&e.classList.remove("active");for(s=this._tabitems.length-1;s>=0;s--)(e=this._tabitems[s]).querySelector("a").hash=="#"+t?e.classList.add("active"):e.classList.contains("active")&&e.classList.remove("active");return this.element.classList.contains("collapsed")&&this.element.classList.remove("collapsed"),this},ol.control.Sidebar.prototype.close=function(){for(var t=this._tabitems.length-1;t>=0;t--){var s=this._tabitems[t];s.classList.contains("active")&&s.classList.remove("active")}return this.element.classList.contains("collapsed")||this.element.classList.add("collapsed"),this},ol.control.Sidebar.prototype._onClick=function(){this.classList.contains("active")?this._sidebar.close():this.classList.contains("disabled")||this._sidebar.open(this.querySelector("a").hash.slice(1))},ol.control.Sidebar.prototype._onCloseClick=function(){this.close()}; -------------------------------------------------------------------------------- /xoroshiro.py: -------------------------------------------------------------------------------- 1 | """Xoroshiro Random Number Generator""" 2 | class XOROSHIRO: 3 | """Xoroshiro Random Number Generator""" 4 | ulongmask = 2 ** 64 - 1 5 | uintmask = 2 ** 32 - 1 6 | 7 | def __init__(self, seed0, seed1 = 0x82A2B175229D6A5B): 8 | self.seed = [seed0, seed1] 9 | 10 | def reseed(self, seed0, seed1 = 0x82A2B175229D6A5B): 11 | """Reseed rng without creating a new object""" 12 | self.seed = [seed0, seed1] 13 | 14 | @property 15 | def state(self): 16 | """Return the full state of the rng as read from memory""" 17 | seed0, seed1 = self.seed 18 | return seed0 | (seed1 << 64) 19 | 20 | @staticmethod 21 | def rotl(number, k): 22 | """Rotate number left by k""" 23 | return ((number << k) | (number >> (64 - k))) & XOROSHIRO.ulongmask 24 | 25 | def next(self): 26 | """Generate the next random number and advance the rng""" 27 | seed0, seed1 = self.seed 28 | result = (seed0 + seed1) & XOROSHIRO.ulongmask 29 | seed1 ^= seed0 30 | self.seed = [XOROSHIRO.rotl(seed0, 24) ^ seed1 ^ ((seed1 << 16) & XOROSHIRO.ulongmask), 31 | XOROSHIRO.rotl(seed1, 37)] 32 | return result 33 | 34 | def previous(self): 35 | """Generate the previous random number and advance the rng backwards""" 36 | seed0, seed1 = self.seed 37 | seed1 = XOROSHIRO.rotl(seed1, 27) 38 | seed0 = (seed0 ^ seed1 ^ (seed1 << 16)) & XOROSHIRO.ulongmask 39 | seed0 = XOROSHIRO.rotl(seed0, 40) 40 | seed1 ^= seed0 41 | self.seed = [seed0,seed1] 42 | return (seed0 + seed1) & XOROSHIRO.ulongmask 43 | 44 | def nextuint(self): 45 | """Generate the next random number as a uint""" 46 | return self.next() & XOROSHIRO.uintmask 47 | 48 | @staticmethod 49 | def get_mask(maximum): 50 | """Get the bit mask for rand(maximum)""" 51 | maximum -= 1 52 | for i in range(6): 53 | maximum |= maximum >> (1 << i) 54 | return maximum 55 | 56 | def rand(self, maximum = uintmask): 57 | """Generate a random number in the range of [0,maximum)""" 58 | mask = XOROSHIRO.get_mask(maximum) 59 | res = self.next() & mask 60 | while res >= maximum: 61 | res = self.next() & mask 62 | return res 63 | -------------------------------------------------------------------------------- /static/sidebar-v2/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var clean = require('gulp-clean'); 3 | var csslint = require('gulp-csslint'); 4 | var jshint = require('gulp-jshint'); 5 | var minifyCSS = require('gulp-minify-css'); 6 | var sass = require('gulp-sass'); 7 | var rename = require('gulp-rename'); 8 | var uglify = require('gulp-uglify'); 9 | var zip = require('gulp-zip'); 10 | 11 | var pkg = require('./package.json'); 12 | var basename = pkg.name + '-' + pkg.version; 13 | 14 | // SASS compilation 15 | gulp.task('sass', function () { 16 | gulp.src('scss/*sidebar.scss') 17 | .pipe(sass().on('error', sass.logError)) 18 | .pipe(gulp.dest('css')); 19 | }); 20 | 21 | // Lint JS + CSS 22 | gulp.task('lint', ['lint:js', 'lint:css']); 23 | 24 | gulp.task('lint:js', function() { 25 | return gulp.src('js/*sidebar.js') 26 | .pipe(jshint()) 27 | .pipe(jshint.reporter()); 28 | }); 29 | 30 | gulp.task('lint:css', ['sass'], function() { 31 | return gulp.src('css/*sidebar.css') 32 | .pipe(csslint({ 33 | 'adjoining-classes': false, 34 | 'order-alphabetical': false, 35 | 'box-sizing': false, 36 | 'fallback-colors': false, 37 | 'important': false, 38 | 'regex-selectors': false, 39 | })) 40 | .pipe(csslint.formatter()); 41 | }); 42 | 43 | // Minify JS + CSS 44 | gulp.task('minify', ['minify:js', 'minify:css']); 45 | 46 | gulp.task('minify:js', function() { 47 | return gulp.src('js/*sidebar.js') 48 | .pipe(rename({ suffix: '.min' })) 49 | .pipe(uglify()) 50 | .pipe(gulp.dest('js')); 51 | }); 52 | 53 | gulp.task('minify:css', ['sass'], function() { 54 | return gulp.src('css/*sidebar.css') 55 | .pipe(rename({ suffix: '.min' })) 56 | .pipe(minifyCSS()) 57 | .pipe(gulp.dest('css')); 58 | }); 59 | 60 | // Package for distribution 61 | gulp.task('zip', ['minify'], function() { 62 | return gulp.src([ 63 | 'README.md', 64 | 'LICENSE', 65 | 'css/*-sidebar.min.css', 66 | 'js/*-sidebar.min.js', 67 | ]) 68 | .pipe(rename(function (path) { 69 | path.dirname = ''; 70 | })) 71 | .pipe(zip(basename + '.zip')) 72 | .pipe(gulp.dest('dist')); 73 | }); 74 | 75 | // Watch JS + CSS Files 76 | gulp.task('watch', ['lint', 'minify'], function(){ 77 | gulp.watch('js/*.js', ['lint:js', 'minify:js']); 78 | gulp.watch('scss/*.scss', ['lint:css', 'minify:css']); 79 | }); 80 | 81 | // Default 82 | gulp.task('default', ['lint', 'minify']); 83 | -------------------------------------------------------------------------------- /static/sidebar-v2/scss/leaflet-sidebar.scss: -------------------------------------------------------------------------------- 1 | $sidebar-margins: 10px !default; 2 | $sidebar-border-radius: 4px !default; 3 | $sidebar-touch-border: 2px solid rgba(0, 0, 0, 0.2) !default; 4 | $sidebar-shadow: 0 1px 5px rgba(0, 0, 0, 0.65) !default; 5 | 6 | $tab-fg: #333 !default; 7 | $tabs-bg: #fff !default; 8 | $tab-hover-fg: #000 !default; 9 | $tab-hover-bg: #eee !default; 10 | $tab-active-fg: #fff !default; 11 | $tab-active-bg: #0074d9 !default; 12 | 13 | @import 'base'; 14 | 15 | .sidebar { 16 | box-shadow: $sidebar-shadow; 17 | 18 | &.leaflet-touch { 19 | box-shadow: none; 20 | border-right: $sidebar-touch-border; 21 | } 22 | 23 | @media(min-width:$threshold-sm) { 24 | border-radius: $sidebar-border-radius; 25 | 26 | &.leaflet-touch { 27 | border: $sidebar-touch-border; 28 | } 29 | } 30 | } 31 | 32 | .sidebar-left { 33 | 34 | & ~ .sidebar-map .leaflet-left { 35 | @media(min-width:$threshold-sm) { 36 | transition: left $sidebar-transition; 37 | } 38 | 39 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 40 | left: $width-sm + $sidebar-margins; 41 | } 42 | 43 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 44 | left: $width-md + $sidebar-margins; 45 | } 46 | 47 | @media(min-width:$threshold-lg) { 48 | left: $width-lg + $sidebar-margins; 49 | } 50 | } 51 | 52 | &.collapsed ~ .sidebar-map .leaflet-left { 53 | @media(min-width:$threshold-sm) { 54 | left: $tab-size + $sidebar-margins; 55 | } 56 | } 57 | } 58 | 59 | .sidebar-right { 60 | 61 | & ~ .sidebar-map .leaflet-right { 62 | @media(min-width:$threshold-sm) { 63 | transition: right $sidebar-transition; 64 | } 65 | 66 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 67 | right: $width-sm + $sidebar-margins; 68 | } 69 | 70 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 71 | right: $width-md + $sidebar-margins; 72 | } 73 | 74 | @media(min-width:$threshold-lg) { 75 | right: $width-lg + $sidebar-margins; 76 | } 77 | } 78 | 79 | &.collapsed ~ .sidebar-map .leaflet-right { 80 | @media(min-width:$threshold-sm) { 81 | right: $tab-size + $sidebar-margins; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Config 132 | config.json 133 | 134 | # vscode 135 | .vscode/ -------------------------------------------------------------------------------- /static/sidebar-v2/scss/ol3-sidebar.scss: -------------------------------------------------------------------------------- 1 | $sidebar-margins: 6px !default; 2 | $sidebar-inner-border-radius: 2px !default; 3 | 4 | @import 'ol-base'; 5 | 6 | .sidebar-left { 7 | 8 | & ~ .sidebar-map { 9 | 10 | .ol-zoom, .ol-scale-line { 11 | margin-left: $tab-size + $sidebar-border-width * 2; 12 | 13 | @media(min-width: $threshold-sm) { 14 | transition: margin-left $sidebar-transition; 15 | } 16 | 17 | @media(min-width: $threshold-sm) and (max-width: $threshold-md - 1px) { 18 | margin-left: $width-sm + $sidebar-margins + $sidebar-border-width * 2; 19 | } 20 | 21 | @media(min-width: $threshold-md) and (max-width: $threshold-lg - 1px) { 22 | margin-left: $width-md + $sidebar-margins + $sidebar-border-width * 2; 23 | } 24 | 25 | @media(min-width: $threshold-lg) { 26 | margin-left: $width-lg + $sidebar-margins + $sidebar-border-width * 2; 27 | } 28 | } 29 | } 30 | 31 | &.collapsed ~ .sidebar-map { 32 | 33 | .ol-zoom, .ol-scale-line { 34 | @media(min-width:$threshold-sm) { 35 | margin-left: $tab-size + $sidebar-margins + $sidebar-border-width * 2; 36 | } 37 | } 38 | } 39 | } 40 | 41 | 42 | .sidebar-right { 43 | 44 | & ~ .sidebar-map { 45 | 46 | .ol-rotate, 47 | .ol-attribution, 48 | .ol-full-screen { 49 | 50 | margin-right: $tab-size + $sidebar-border-width * 2; 51 | 52 | @media(min-width: $threshold-sm) { 53 | transition: margin-right $sidebar-transition; 54 | } 55 | 56 | @media(min-width: $threshold-sm) and (max-width: $threshold-md - 1px) { 57 | margin-right: $width-sm + $sidebar-margins + $sidebar-border-width * 2; 58 | } 59 | 60 | @media(min-width: $threshold-md) and (max-width: $threshold-lg - 1px) { 61 | margin-right: $width-md + $sidebar-margins + $sidebar-border-width * 2; 62 | } 63 | 64 | @media(min-width: $threshold-lg) { 65 | margin-right: $width-lg + $sidebar-margins + $sidebar-border-width * 2; 66 | } 67 | } 68 | } 69 | 70 | &.collapsed ~ .sidebar-map { 71 | 72 | .ol-rotate, 73 | .ol-attribution, 74 | .ol-full-screen { 75 | 76 | @media(min-width:$threshold-sm) { 77 | margin-right: $tab-size + $sidebar-margins + $sidebar-border-width * 2; 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /static/sidebar-v2/scss/ol2-sidebar.scss: -------------------------------------------------------------------------------- 1 | $sidebar-margins: 8px !default; 2 | $sidebar-inner-border-radius: 4px !default; 3 | 4 | @import 'ol-base'; 5 | 6 | .sidebar-left { 7 | 8 | & ~ .sidebar-map { 9 | 10 | .olControlZoom, 11 | .olScaleLine { 12 | margin-left: $tab-size + $sidebar-border-width * 2; 13 | 14 | @media(min-width: $threshold-sm) { 15 | transition: margin-left $sidebar-transition; 16 | } 17 | 18 | @media(min-width: $threshold-sm) and (max-width: $threshold-md - 1px) { 19 | margin-left: $width-sm + $sidebar-margins + $sidebar-border-width * 2; 20 | } 21 | 22 | @media(min-width: $threshold-md) and (max-width: $threshold-lg - 1px) { 23 | margin-left: $width-md + $sidebar-margins + $sidebar-border-width * 2; 24 | } 25 | 26 | @media(min-width: $threshold-lg) { 27 | margin-left: $width-lg + $sidebar-margins + $sidebar-border-width * 2; 28 | } 29 | } 30 | } 31 | 32 | &.collapsed ~ .sidebar-map { 33 | 34 | .olControlZoom, 35 | .olScaleLine { 36 | @media(min-width:$threshold-sm) { 37 | margin-left: $tab-size + $sidebar-margins + $sidebar-border-width * 2; 38 | } 39 | } 40 | } 41 | } 42 | 43 | .sidebar-right { 44 | 45 | & ~ .sidebar-map { 46 | 47 | .olControlAttribution, 48 | .olControlPermalink, 49 | .olControlMousePosition { 50 | margin-right: $tab-size + $sidebar-border-width * 2; 51 | 52 | @media(min-width: $threshold-sm) { 53 | transition: margin-right $sidebar-transition; 54 | } 55 | 56 | @media(min-width: $threshold-sm) and (max-width: $threshold-md - 1px) { 57 | margin-right: $width-sm + $sidebar-margins + $sidebar-border-width * 2; 58 | } 59 | 60 | @media(min-width: $threshold-md) and (max-width: $threshold-lg - 1px) { 61 | margin-right: $width-md + $sidebar-margins + $sidebar-border-width * 2; 62 | } 63 | 64 | @media(min-width: $threshold-lg) { 65 | margin-right: $width-lg + $sidebar-margins + $sidebar-border-width * 2; 66 | } 67 | } 68 | } 69 | 70 | &.collapsed ~ .sidebar-map { 71 | 72 | .olControlAttribution, 73 | .olControlPermalink, 74 | .olControlMousePosition { 75 | @media(min-width:$threshold-sm) { 76 | margin-right: $tab-size + $sidebar-margins + $sidebar-border-width * 2; 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /static/sidebar-v2/js/jquery-sidebar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new sidebar on this jQuery object. 3 | * 4 | * @example 5 | * var sidebar = $('#sidebar').sidebar(); 6 | * 7 | * @param {Object} [options] - Optional options object 8 | * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right' 9 | * @returns {jQuery} 10 | */ 11 | $.fn.sidebar = function(options) { 12 | var $sidebar = this; 13 | var $tabs = $sidebar.find('ul.sidebar-tabs, .sidebar-tabs > ul'); 14 | var $container = $sidebar.children('.sidebar-content').first(); 15 | 16 | options = $.extend({ 17 | position: 'left' 18 | }, options || {}); 19 | 20 | $sidebar.addClass('sidebar-' + options.position); 21 | 22 | $tabs.children('li').children('a[href^="#"]').on('click', function(e) { 23 | e.preventDefault(); 24 | var $tab = $(this).closest('li'); 25 | 26 | if ($tab.hasClass('active')) 27 | $sidebar.close(); 28 | else if (!$tab.hasClass('disabled')) 29 | $sidebar.open(this.hash.slice(1), $tab); 30 | }); 31 | 32 | $sidebar.find('.sidebar-close').on('click', function() { 33 | $sidebar.close(); 34 | }); 35 | 36 | /** 37 | * Open sidebar (if necessary) and show the specified tab. 38 | * 39 | * @param {string} id - The id of the tab to show (without the # character) 40 | * @param {jQuery} [$tab] - The jQuery object representing the tab node (used internally for efficiency) 41 | */ 42 | $sidebar.open = function(id, $tab) { 43 | if (typeof $tab === 'undefined') 44 | $tab = $tabs.find('li > a[href="#' + id + '"]').parent(); 45 | 46 | // hide old active contents 47 | $container.children('.sidebar-pane.active').removeClass('active'); 48 | 49 | // show new content 50 | $container.children('#' + id).addClass('active'); 51 | 52 | // remove old active highlights 53 | $tabs.children('li.active').removeClass('active'); 54 | 55 | // set new highlight 56 | $tab.addClass('active'); 57 | 58 | $sidebar.trigger('content', { 'id': id }); 59 | 60 | if ($sidebar.hasClass('collapsed')) { 61 | // open sidebar 62 | $sidebar.trigger('opening'); 63 | $sidebar.removeClass('collapsed'); 64 | } 65 | }; 66 | 67 | /** 68 | * Close the sidebar (if necessary). 69 | */ 70 | $sidebar.close = function() { 71 | // remove old active highlights 72 | $tabs.children('li.active').removeClass('active'); 73 | 74 | if (!$sidebar.hasClass('collapsed')) { 75 | // close sidebar 76 | $sidebar.trigger('closing'); 77 | $sidebar.addClass('collapsed'); 78 | } 79 | }; 80 | 81 | return $sidebar; 82 | }; 83 | -------------------------------------------------------------------------------- /static/sidebar-v2/js/leaflet-sidebar.min.js: -------------------------------------------------------------------------------- 1 | L.Control.Sidebar=L.Control.extend({includes:L.Evented.prototype||L.Mixin.Events,options:{position:"left"},initialize:function(t,s){var i,e;for(L.setOptions(this,s),this._sidebar=L.DomUtil.get(t),L.DomUtil.addClass(this._sidebar,"sidebar-"+this.options.position),L.Browser.touch&&L.DomUtil.addClass(this._sidebar,"leaflet-touch"),i=this._sidebar.children.length-1;i>=0;i--)"DIV"==(e=this._sidebar.children[i]).tagName&&L.DomUtil.hasClass(e,"sidebar-content")&&(this._container=e);for(this._tabitems=this._sidebar.querySelectorAll("ul.sidebar-tabs > li, .sidebar-tabs > ul > li"),i=this._tabitems.length-1;i>=0;i--)this._tabitems[i]._sidebar=this;for(this._panes=[],this._closeButtons=[],i=this._container.children.length-1;i>=0;i--)if("DIV"==(e=this._container.children[i]).tagName&&L.DomUtil.hasClass(e,"sidebar-pane")){this._panes.push(e);for(var o=e.querySelectorAll(".sidebar-close"),a=0,l=o.length;a=0;s--){var e=(i=this._tabitems[s]).querySelector("a");e.hasAttribute("href")&&"#"==e.getAttribute("href").slice(0,1)&&L.DomEvent.on(e,"click",L.DomEvent.preventDefault).on(e,"click",this._onClick,i)}for(s=this._closeButtons.length-1;s>=0;s--)i=this._closeButtons[s],L.DomEvent.on(i,"click",this._onCloseClick,this);return this},removeFrom:function(t){console.log("removeFrom() has been deprecated, please use remove() instead as support for this function will be ending soon."),this.remove(t)},remove:function(t){var s,i;for(this._map=null,s=this._tabitems.length-1;s>=0;s--)i=this._tabitems[s],L.DomEvent.off(i.querySelector("a"),"click",this._onClick);for(s=this._closeButtons.length-1;s>=0;s--)i=this._closeButtons[s],L.DomEvent.off(i,"click",this._onCloseClick,this);return this},open:function(t){var s,i;for(s=this._panes.length-1;s>=0;s--)(i=this._panes[s]).id==t?L.DomUtil.addClass(i,"active"):L.DomUtil.hasClass(i,"active")&&L.DomUtil.removeClass(i,"active");for(s=this._tabitems.length-1;s>=0;s--)(i=this._tabitems[s]).querySelector("a").hash=="#"+t?L.DomUtil.addClass(i,"active"):L.DomUtil.hasClass(i,"active")&&L.DomUtil.removeClass(i,"active");return this.fire("content",{id:t}),L.DomUtil.hasClass(this._sidebar,"collapsed")&&(this.fire("opening"),L.DomUtil.removeClass(this._sidebar,"collapsed")),this},close:function(){for(var t=this._tabitems.length-1;t>=0;t--){var s=this._tabitems[t];L.DomUtil.hasClass(s,"active")&&L.DomUtil.removeClass(s,"active")}return L.DomUtil.hasClass(this._sidebar,"collapsed")||(this.fire("closing"),L.DomUtil.addClass(this._sidebar,"collapsed")),this},_onClick:function(){L.DomUtil.hasClass(this,"active")?this._sidebar.close():L.DomUtil.hasClass(this,"disabled")||this._sidebar.open(this.querySelector("a").hash.slice(1))},_onCloseClick:function(){this.close()}}),L.control.sidebar=function(t,s){return new L.Control.Sidebar(t,s)}; -------------------------------------------------------------------------------- /static/sidebar-v2/scss/gmaps-sidebar.scss: -------------------------------------------------------------------------------- 1 | $sidebar-margins: 10px !default; 2 | $sidebar-left-bottom-margin: $sidebar-margins + 25px !default; 3 | $sidebar-right-bottom-margin: $sidebar-margins + 14px !default; 4 | $sidebar-border: 0 !default; 5 | $sidebar-border-radius: 2px !default; 6 | $sidebar-shadow: rgba(0, 0, 0, 0.298039) 0 1px 4px -1px !default; 7 | 8 | $tab-fg: #666 !default; 9 | $tabs-bg: #fff !default; 10 | $tab-active-fg: #000 !default; 11 | $tab-active-bg: #febf00 !default; 12 | $tab-hover-fg: #000 !default; 13 | $tab-hover-bg: ($tabs-bg * 9 + $tab-active-bg) / 10 !default; 14 | 15 | @import 'base'; 16 | 17 | .sidebar { 18 | border-right: $sidebar-border; 19 | box-shadow: $sidebar-shadow; 20 | 21 | @media(min-width:$threshold-sm) { 22 | border: $sidebar-border; 23 | border-radius: $sidebar-border-radius; 24 | } 25 | } 26 | 27 | .sidebar-left { 28 | @media(min-width:$threshold-sm) { 29 | bottom: $sidebar-left-bottom-margin; 30 | } 31 | 32 | & ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 33 | @media(min-width:$threshold-sm) { 34 | transition: margin-left $sidebar-transition; 35 | } 36 | 37 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 38 | margin-left: $width-sm + $sidebar-margins * 2 !important; 39 | } 40 | 41 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 42 | margin-left: $width-md + $sidebar-margins * 2 !important; 43 | } 44 | 45 | @media(min-width:$threshold-lg) { 46 | margin-left: $width-lg + $sidebar-margins * 2 !important; 47 | } 48 | } 49 | 50 | @media(min-width:$threshold-sm) { 51 | &.collapsed ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 52 | margin-left: $tab-size + $sidebar-margins * 2 !important; 53 | } 54 | } 55 | } 56 | 57 | 58 | .sidebar-right { 59 | @media(min-width:$threshold-sm) { 60 | bottom: $sidebar-right-bottom-margin; 61 | } 62 | 63 | & ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 64 | @media(min-width:$threshold-sm) { 65 | transition: margin-right $sidebar-transition; 66 | } 67 | 68 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 69 | margin-right: $width-sm + $sidebar-margins * 2 !important; 70 | } 71 | 72 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 73 | margin-right: $width-md + $sidebar-margins * 2 !important; 74 | } 75 | 76 | @media(min-width:$threshold-lg) { 77 | margin-right: $width-lg + $sidebar-margins * 2 !important; 78 | } 79 | } 80 | 81 | @media(min-width:$threshold-sm) { 82 | &.collapsed ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 83 | margin-right: $tab-size + $sidebar-margins * 2 !important; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /static/sidebar-v2/css/leaflet-sidebar.min.css: -------------------------------------------------------------------------------- 1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000;box-shadow:0 1px 5px rgba(0,0,0,.65)}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0}.sidebar-right{right:0}@media (min-width:768px){.sidebar{top:10px;bottom:10px;transition:width .5s}.sidebar-left{left:10px}.sidebar-right{right:10px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:#fff}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0;list-style-type:none}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#333;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#000;background-color:#eee}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(51,51,51,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar-left~.sidebar-map{margin-left:40px}.sidebar-right~.sidebar-map{margin-right:40px}.sidebar.leaflet-touch{box-shadow:none;border-right:2px solid rgba(0,0,0,.2)}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .leaflet-left{left:315px}.sidebar-right~.sidebar-map .leaflet-right{right:315px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .leaflet-left{left:400px}.sidebar-right~.sidebar-map .leaflet-right{right:400px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .leaflet-left{left:470px}.sidebar-right~.sidebar-map .leaflet-right{right:470px}}@media (min-width:768px){.sidebar-left~.sidebar-map{margin-left:0}.sidebar-right~.sidebar-map{margin-right:0}.sidebar{border-radius:4px}.sidebar.leaflet-touch{border:2px solid rgba(0,0,0,.2)}.sidebar-left~.sidebar-map .leaflet-left{transition:left .5s}.sidebar-left.collapsed~.sidebar-map .leaflet-left{left:50px}.sidebar-right~.sidebar-map .leaflet-right{transition:right .5s}.sidebar-right.collapsed~.sidebar-map .leaflet-right{right:50px}} -------------------------------------------------------------------------------- /static/sidebar-v2/css/gmaps-sidebar.min.css: -------------------------------------------------------------------------------- 1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000;border-right:0;box-shadow:rgba(0,0,0,.298039) 0 1px 4px -1px}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0}.sidebar-right{right:0}@media (min-width:768px){.sidebar{top:10px;bottom:10px;transition:width .5s}.sidebar-left{left:10px}.sidebar-right{right:10px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:#fff}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0;list-style-type:none}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#666;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#000;background-color:#fff9e6}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#000;background-color:#febf00}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(102,102,102,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#000;background-color:#febf00}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar-left~.sidebar-map{margin-left:40px}.sidebar-right~.sidebar-map{margin-right:40px}@media (min-width:768px){.sidebar-left~.sidebar-map{margin-left:0}.sidebar-right~.sidebar-map{margin-right:0}.sidebar{border:0;border-radius:2px}.sidebar-left{bottom:35px}.sidebar-left~.sidebar-map .gm-style>div.gmnoprint[style*="left: 0px"]{transition:margin-left .5s}}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .gm-style>div.gmnoprint[style*="left: 0px"]{margin-left:325px!important}.sidebar-right~.sidebar-map .gm-style>div.gmnoprint[style*="right: 28px"]{margin-right:325px!important}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .gm-style>div.gmnoprint[style*="left: 0px"]{margin-left:410px!important}.sidebar-right~.sidebar-map .gm-style>div.gmnoprint[style*="right: 28px"]{margin-right:410px!important}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .gm-style>div.gmnoprint[style*="left: 0px"]{margin-left:480px!important}.sidebar-right~.sidebar-map .gm-style>div.gmnoprint[style*="right: 28px"]{margin-right:480px!important}}@media (min-width:768px){.sidebar-left.collapsed~.sidebar-map .gm-style>div.gmnoprint[style*="left: 0px"]{margin-left:60px!important}.sidebar-right{bottom:24px}.sidebar-right~.sidebar-map .gm-style>div.gmnoprint[style*="right: 28px"]{transition:margin-right .5s}.sidebar-right.collapsed~.sidebar-map .gm-style>div.gmnoprint[style*="right: 28px"]{margin-right:60px!important}} -------------------------------------------------------------------------------- /static/sidebar-v2/css/ol3-sidebar.min.css: -------------------------------------------------------------------------------- 1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0;border-right:3px solid transparent}.sidebar-right{right:0;border-left:3px solid transparent}@media (min-width:768px){.sidebar{top:6px;bottom:6px;transition:width .5s;border:3px solid transparent;border-radius:4px}.sidebar-left{left:6px}.sidebar-right{right:6px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:rgba(0,60,136,.5)}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0;list-style-type:none}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#fff;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#fff;background-color:rgba(0,60,136,.6)}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(255,255,255,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar{background-color:rgba(255,255,255,.4)}.sidebar-tabs{overflow:hidden}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:46px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:46px}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:317px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:317px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:402px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:402px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{margin-left:472px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{margin-right:472px}}@media (min-width:768px){.sidebar-tabs{border-radius:2px 0 0 2px}.collapsed .sidebar-tabs{border-radius:2px}.sidebar-content{border-radius:0 2px 2px 0}.sidebar-left~.sidebar-map .ol-scale-line,.sidebar-left~.sidebar-map .ol-zoom{transition:margin-left .5s}.sidebar-left.collapsed~.sidebar-map .ol-scale-line,.sidebar-left.collapsed~.sidebar-map .ol-zoom{margin-left:52px}.sidebar-right~.sidebar-map .ol-attribution,.sidebar-right~.sidebar-map .ol-full-screen,.sidebar-right~.sidebar-map .ol-rotate{transition:margin-right .5s}.sidebar-right.collapsed~.sidebar-map .ol-attribution,.sidebar-right.collapsed~.sidebar-map .ol-full-screen,.sidebar-right.collapsed~.sidebar-map .ol-rotate{margin-right:52px}} -------------------------------------------------------------------------------- /static/sidebar-v2/css/ol2-sidebar.min.css: -------------------------------------------------------------------------------- 1 | .sidebar{position:absolute;top:0;bottom:0;width:100%;overflow:hidden;z-index:2000}.sidebar.collapsed{width:40px}@media (min-width:768px) and (max-width:991px){.sidebar{width:305px}.sidebar-pane{min-width:265px}}@media (min-width:992px) and (max-width:1199px){.sidebar{width:390px}}@media (min-width:1200px){.sidebar{width:460px}}.sidebar-left{left:0;border-right:3px solid transparent}.sidebar-right{right:0;border-left:3px solid transparent}@media (min-width:768px){.sidebar{top:8px;bottom:8px;transition:width .5s;border:3px solid transparent;border-radius:4px}.sidebar-left{left:8px}.sidebar-right{right:8px}}.sidebar-tabs{top:0;bottom:0;height:100%;background-color:rgba(0,60,136,.5)}.sidebar-left .sidebar-tabs{left:0}.sidebar-right .sidebar-tabs{right:0}.sidebar-tabs,.sidebar-tabs>ul{position:absolute;width:40px;margin:0;padding:0;list-style-type:none}.sidebar-tabs>li,.sidebar-tabs>ul>li{width:100%;height:40px;color:#fff;font-size:12pt;overflow:hidden;transition:all 80ms}.sidebar-tabs>li:hover,.sidebar-tabs>ul>li:hover{color:#fff;background-color:rgba(0,60,136,.6)}.sidebar-tabs>li.active,.sidebar-tabs>ul>li.active{color:#fff;background-color:#0074d9}.sidebar-tabs>li.disabled,.sidebar-tabs>ul>li.disabled{color:rgba(255,255,255,.4)}.sidebar-tabs>li.disabled:hover,.sidebar-tabs>ul>li.disabled:hover{background:0 0}.sidebar-tabs>li.disabled>a,.sidebar-tabs>ul>li.disabled>a{cursor:default}.sidebar-tabs>li>a,.sidebar-tabs>ul>li>a{display:block;width:100%;height:100%;line-height:40px;color:inherit;text-decoration:none;text-align:center}.sidebar-tabs>ul+ul{bottom:0}.sidebar-content{position:absolute;top:0;bottom:0;background-color:rgba(255,255,255,.95);overflow-x:hidden;overflow-y:auto}.sidebar-left .sidebar-content{left:40px;right:0}.sidebar-right .sidebar-content{left:0;right:40px}.sidebar.collapsed>.sidebar-content{overflow-y:hidden}.sidebar-pane{display:none;left:0;right:0;box-sizing:border-box;padding:10px 20px}.sidebar-pane.active{display:block}.sidebar-header{margin:-10px -20px 0;height:40px;padding:0 20px;line-height:40px;font-size:14.4pt;color:#fff;background-color:#0074d9}.sidebar-right .sidebar-header{padding-left:40px}.sidebar-close{position:absolute;top:0;width:40px;height:40px;text-align:center;cursor:pointer}.sidebar-left .sidebar-close{right:0}.sidebar-right .sidebar-close{left:0}.sidebar{background-color:rgba(255,255,255,.4)}.sidebar-tabs{overflow:hidden}.sidebar-left~.sidebar-map .olControlZoom,.sidebar-left~.sidebar-map .olScaleLine{margin-left:46px}.sidebar-right~.sidebar-map .olControlAttribution,.sidebar-right~.sidebar-map .olControlMousePosition,.sidebar-right~.sidebar-map .olControlPermalink{margin-right:46px}@media (min-width:768px) and (max-width:991px){.sidebar-left~.sidebar-map .olControlZoom,.sidebar-left~.sidebar-map .olScaleLine{margin-left:319px}.sidebar-right~.sidebar-map .olControlAttribution,.sidebar-right~.sidebar-map .olControlMousePosition,.sidebar-right~.sidebar-map .olControlPermalink{margin-right:319px}}@media (min-width:992px) and (max-width:1199px){.sidebar-pane{min-width:350px}.sidebar-left~.sidebar-map .olControlZoom,.sidebar-left~.sidebar-map .olScaleLine{margin-left:404px}.sidebar-right~.sidebar-map .olControlAttribution,.sidebar-right~.sidebar-map .olControlMousePosition,.sidebar-right~.sidebar-map .olControlPermalink{margin-right:404px}}@media (min-width:1200px){.sidebar-pane{min-width:420px}.sidebar-left~.sidebar-map .olControlZoom,.sidebar-left~.sidebar-map .olScaleLine{margin-left:474px}.sidebar-right~.sidebar-map .olControlAttribution,.sidebar-right~.sidebar-map .olControlMousePosition,.sidebar-right~.sidebar-map .olControlPermalink{margin-right:474px}}@media (min-width:768px){.sidebar-tabs{border-radius:4px 0 0 4px}.collapsed .sidebar-tabs{border-radius:4px}.sidebar-content{border-radius:0 4px 4px 0}.sidebar-left~.sidebar-map .olControlZoom,.sidebar-left~.sidebar-map .olScaleLine{transition:margin-left .5s}.sidebar-left.collapsed~.sidebar-map .olControlZoom,.sidebar-left.collapsed~.sidebar-map .olScaleLine{margin-left:54px}.sidebar-right~.sidebar-map .olControlAttribution,.sidebar-right~.sidebar-map .olControlMousePosition,.sidebar-right~.sidebar-map .olControlPermalink{transition:margin-right .5s}.sidebar-right.collapsed~.sidebar-map .olControlAttribution,.sidebar-right.collapsed~.sidebar-map .olControlMousePosition,.sidebar-right.collapsed~.sidebar-map .olControlPermalink{margin-right:54px}} -------------------------------------------------------------------------------- /static/sidebar-v2/js/ol3-sidebar.js: -------------------------------------------------------------------------------- 1 | ol.control.Sidebar = function (settings) { 2 | 3 | var defaults = { 4 | element: null, 5 | position: 'left' 6 | }, i, child; 7 | 8 | this._options = Object.assign({}, defaults, settings); 9 | 10 | ol.control.Control.call(this, { 11 | element: document.getElementById(this._options.element), 12 | target: this._options.target 13 | }); 14 | 15 | // Attach .sidebar-left/right class 16 | this.element.classList.add('sidebar-' + this._options.position); 17 | 18 | // Find sidebar > div.sidebar-content 19 | for (i = this.element.children.length - 1; i >= 0; i--) { 20 | child = this.element.children[i]; 21 | if (child.tagName === 'DIV' && 22 | child.classList.contains('sidebar-content')) { 23 | this._container = child; 24 | } 25 | } 26 | 27 | // Find sidebar ul.sidebar-tabs > li, sidebar .sidebar-tabs > ul > li 28 | this._tabitems = this.element.querySelectorAll('ul.sidebar-tabs > li, .sidebar-tabs > ul > li'); 29 | for (i = this._tabitems.length - 1; i >= 0; i--) { 30 | this._tabitems[i]._sidebar = this; 31 | } 32 | 33 | // Find sidebar > div.sidebar-content > div.sidebar-pane 34 | this._panes = []; 35 | this._closeButtons = []; 36 | for (i = this._container.children.length - 1; i >= 0; i--) { 37 | child = this._container.children[i]; 38 | if (child.tagName == 'DIV' && 39 | child.classList.contains('sidebar-pane')) { 40 | this._panes.push(child); 41 | 42 | var closeButtons = child.querySelectorAll('.sidebar-close'); 43 | for (var j = 0, len = closeButtons.length; j < len; j++) { 44 | this._closeButtons.push(closeButtons[j]); 45 | } 46 | } 47 | } 48 | }; 49 | 50 | ol.inherits(ol.control.Sidebar, ol.control.Control); 51 | 52 | ol.control.Sidebar.prototype.setMap = function(map) { 53 | var i, child; 54 | 55 | for (i = this._tabitems.length - 1; i >= 0; i--) { 56 | child = this._tabitems[i]; 57 | var sub = child.querySelector('a'); 58 | if (sub.hasAttribute('href') && sub.getAttribute('href').slice(0,1) == '#') { 59 | sub.onclick = this._onClick.bind(child); 60 | } 61 | } 62 | 63 | for (i = this._closeButtons.length - 1; i >= 0; i--) { 64 | child = this._closeButtons[i]; 65 | child.onclick = this._onCloseClick.bind(this); 66 | } 67 | }; 68 | 69 | ol.control.Sidebar.prototype.open = function(id) { 70 | var i, child; 71 | 72 | // hide old active contents and show new content 73 | for (i = this._panes.length - 1; i >= 0; i--) { 74 | child = this._panes[i]; 75 | if (child.id == id) 76 | child.classList.add('active'); 77 | else if (child.classList.contains('active')) 78 | child.classList.remove('active'); 79 | } 80 | 81 | // remove old active highlights and set new highlight 82 | for (i = this._tabitems.length - 1; i >= 0; i--) { 83 | child = this._tabitems[i]; 84 | if (child.querySelector('a').hash == '#' + id) 85 | child.classList.add('active'); 86 | else if (child.classList.contains('active')) 87 | child.classList.remove('active'); 88 | } 89 | 90 | // open sidebar (if necessary) 91 | if (this.element.classList.contains('collapsed')) { 92 | this.element.classList.remove('collapsed'); 93 | } 94 | 95 | return this; 96 | }; 97 | 98 | ol.control.Sidebar.prototype.close = function() { 99 | // remove old active highlights 100 | for (var i = this._tabitems.length - 1; i >= 0; i--) { 101 | var child = this._tabitems[i]; 102 | if (child.classList.contains('active')) 103 | child.classList.remove('active'); 104 | } 105 | 106 | // close sidebar 107 | if (!this.element.classList.contains('collapsed')) { 108 | this.element.classList.add('collapsed'); 109 | } 110 | 111 | return this; 112 | }; 113 | 114 | ol.control.Sidebar.prototype._onClick = function() { 115 | if (this.classList.contains('active')) { 116 | this._sidebar.close(); 117 | } else if (!this.classList.contains('disabled')) { 118 | this._sidebar.open(this.querySelector('a').hash.slice(1)); 119 | } 120 | }; 121 | 122 | ol.control.Sidebar.prototype._onCloseClick = function() { 123 | this.close(); 124 | }; 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PLA-Live-Map 2 | Flask application that displays live information on an interactive map for Pokemon Legends: Arceus. 3 | ![](./Map_Screenshot.png) 4 | 5 | ## PLA-Live-Map uses [sysbot-base](https://github.com/olliz0r/sys-botbase) to connect to the switch, and this must be installed on your console 6 | 7 | # How to run: 8 | 1. Install requirements ``pip install -r requirements.txt`` 9 | 2. Copy-paste ``config.json.template`` and rename to ``config.json`` 10 | 3. Edit the ``IP`` field to contain your switch's IP 11 | 4. Run main.py ``python3 ./main.py`` 12 | 5. Open ``http://localhost:8080/`` in your browser 13 | 6. Select your current map 14 | 15 | # Troubleshooting 16 | - What does ``FileNotFoundError: [Errno 2] No such file or directory: 'config.json'`` mean? 17 | - This error means the script could not find your config file in the directory its being run, make sure youre running the script from cmd in the project's directory, and that you've actually renamed ``config.json.template`` to ``config.json``. 18 | 19 | - I'm getting ``ModuleNotFoundError: No module named 'requests'`` even though the pip install command runs fine! 20 | - Make sure that you do not have multiple python versions installed, and **DO NOT USE THE WINDOWS STORE PYTHON**. You can uninstall versions by searching "Uninstall" in your windows search bar and selecting "Add or remove program". 21 | - Windows tells me ``Python was not found; run without arguments to install form the Microsoft Store...`` but I thought we didnt want windows store python? 22 | - Windows does this whenever it cant detect an already installed version and you try to use python, you can disable this by typing "Manage app execution aliases" in your windows search bar and deselecting python and python3. 23 | - The script is telling me ``TimeoutError: timed out``, what does this mean? 24 | - This error is a general connection error, common causes include: 25 | - The ip in your config.json is not your switch's actual ip. 26 | - The switch is not connected to the same internet as your pc. 27 | - Your internet connection is failing. 28 | - When I click on a marker I get ``binascii.Error: Odd-length string`` 29 | - This error means that sysbot-base gave the script bad data, the cause of this is typically trying to read from memory (this happens when you click on a marker) while its already doing an action. Do not click any markers until the script is done doing whatever action its doing (you can see the progress in the terminal/cmd). 30 | - If this happens once, it may cause sysbot-base to get stuck, to fix this you can restart the script and your console. 31 | - What does ``ConnectionAbortedError`` mean? 32 | - This error happens when something caused the connection to the switch to abruptly stop, make sure your switch and pc are still connected to the internet, and restart the script. 33 | - Nothing is advancing correctly! or Every marker has the same generator seed! or The near shiny button makes a marker green but its way past the limit I have set? 34 | - If you've gotten to this point it means that your pc can connect to your switch, and that sysbot-base is able to send information to your pc. The most common causes of these issues are another program running on the switch that accesses memory. Make sure to not have programs like Edizon or CaptureSight running while you are trying to rng (Edizon might be accessing memory by default if its installed, so it may be best to uninstall it.) 35 | - Also make sure you do not have a mass outbreak active on your map if you are trying to rng a non mass outbreak, this will cause the group ids to be shifted and things will not advance properly. 36 | - Lastly, make sure your game is on the **latest version (1.0.2)** as the pointers used are specific to this version. 37 | 38 | # Current features 39 | - Ability to read all active spawns with "Update Active Spawns" (Pokemon are displayed as a red pokeball) 40 | - Ability to track and display the players current position on the map with "Track Player Position" 41 | - Ability to teleport to any location on the map at the specified height on click with "Teleport" 42 | - Ability to teleport to specific markers on the map with "Teleport to marker id X" in the marker pop-up 43 | - Ability to read the spawner information and next shiny advance of known group ids and/or active pokemon 44 | - Ability to read the current map's mass outbreak information 45 | - Ability to read the pokemon that you are currently in battle with 46 | 47 | # Credits 48 | - berichan's [PLA Warper](https://github.com/berichan/PLAWarper) for the pointer to player location 49 | - Serebii's [Pokearth](https://www.serebii.net/pokearth/hisui/) for the map images 50 | 51 | # Licensed Software 52 | - PLA-Live-Map uses [sidebar-v2](https://github.com/Turbo87/sidebar-v2) which is licensed under the [MIT License](./static/sidebar-v2/LICENSE) -------------------------------------------------------------------------------- /nxreader.py: -------------------------------------------------------------------------------- 1 | """Simplified class to read information from sys-botbase 2 | https://github.com/Lincoln-LM/PyNXReader""" 3 | import socket 4 | import binascii 5 | from time import sleep 6 | 7 | class NXReader: 8 | """Simplified class to read information from sys-botbase""" 9 | def __init__(self, ip_address = None, port = 6000): 10 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 11 | self.socket.settimeout(1) 12 | self.socket.connect((ip_address, port)) 13 | print('Connected') 14 | self.ls_lastx = 0 15 | self.ls_lasty = 0 16 | self.rs_lastx = 0 17 | self.rs_lasty = 0 18 | self._configure() 19 | 20 | def _configure(self): 21 | self.send_command('configure echoCommands 0') 22 | 23 | def send_command(self,content): 24 | """Send a command to sys-botbase on the switch""" 25 | content += '\r\n' #important for the parser on the switch side 26 | self.socket.sendall(content.encode()) 27 | 28 | def recv(self,size): 29 | """Receive response from sys-botbase""" 30 | return binascii.unhexlify(self.socket.recv(2 * size + 1)[0:-1]) 31 | 32 | def close(self): 33 | """Close connection to switch""" 34 | print("Exiting...") 35 | self.pause(0.5) 36 | self.socket.shutdown(socket.SHUT_RDWR) 37 | self.socket.close() 38 | print('Disconnected') 39 | 40 | # A/B/X/Y/LSTICK/RSTICK/L/R/ZL/ZR/PLUS/MINUS/DLEFT/DUP/DDOWN/DRIGHT/HOME/CAPTURE 41 | def click(self,button): 42 | """Press and release button""" 43 | self.send_command('click '+ button) 44 | 45 | def press(self,button): 46 | """Press and hold button""" 47 | self.send_command('press '+ button) 48 | 49 | def release(self,button): 50 | """Release held button""" 51 | self.send_command('release '+ button) 52 | 53 | # setStick LEFT/RIGHT 75 | #poke
    76 | def read(self,address,size,filename = None): 77 | """Read bytes from heap""" 78 | self.send_command(f'peek 0x{address:X} 0x{size:X}') 79 | sleep(size/0x8000) 80 | buf = self.recv(size) 81 | if filename is not None: 82 | if filename == '': 83 | filename = f'dump_heap_0x{address:X}_0x{size:X}.bin' 84 | with open(filename,'wb') as file_out: 85 | file_out.write(buf) 86 | return buf 87 | 88 | def read_int(self,address,size,filename = None): 89 | """Read integer from heap""" 90 | return int.from_bytes(self.read(address,size,filename),'little') 91 | 92 | def write(self,address,data): 93 | """Write data to heap""" 94 | self.send_command(f'poke 0x{address:X} 0x{data}') 95 | 96 | def read_main(self,address,size,filename = None): 97 | """Read bytes from main""" 98 | self.send_command(f'peekMain 0x{address:X} 0x{size:X}') 99 | sleep(size/0x8000) 100 | buf = self.recv(size) 101 | if filename is not None: 102 | if filename == '': 103 | filename = f'dump_heap_0x{address:X}_0x{size:X}.bin' 104 | with open(filename,'wb') as file_out: 105 | file_out.write(buf) 106 | return buf 107 | 108 | def read_main_int(self,address,size,filename = None): 109 | """Read integer from main""" 110 | return int.from_bytes(self.read_main(address,size,filename),'little') 111 | 112 | def write_main(self,address,data): 113 | """Write data to main""" 114 | self.send_command(f'pokeMain 0x{address:X} 0x{data}') 115 | 116 | def read_pointer(self,pointer,size,filename = None): 117 | """Read bytes from pointer""" 118 | jumps = pointer.replace("[","").replace("main","").split("]") 119 | command = f'pointerPeek 0x{size:X} 0x{" 0x".join(jump.replace("+","") for jump in jumps)}' 120 | self.send_command(command) 121 | sleep(size/0x8000) 122 | buf = self.recv(size) 123 | if filename is not None: 124 | if filename == '': 125 | filename = f'dump_heap_{pointer}_0x{size:X}.bin' 126 | with open(filename,'wb') as file_out: 127 | file_out.write(buf) 128 | return buf 129 | 130 | def read_pointer_int(self,pointer,size,filename = None): 131 | """Read integer from pointer""" 132 | return int.from_bytes(self.read_pointer(pointer,size,filename = filename),'little') 133 | 134 | def write_pointer(self,pointer,data): 135 | """Write data to pointer""" 136 | jumps = pointer.replace("[","").replace("main","").split("]") 137 | command = f'pointerPoke 0x{data} 0x{" 0x".join(jump.replace("+","") for jump in jumps)}' 138 | self.send_command(command) 139 | 140 | @staticmethod 141 | def pause(duration): 142 | """Pause connection to switch""" 143 | sleep(duration) 144 | -------------------------------------------------------------------------------- /static/sidebar-v2/css/leaflet-sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | overflow: hidden; 7 | z-index: 2000; } 8 | .sidebar.collapsed { 9 | width: 40px; } 10 | @media (min-width: 768px) { 11 | .sidebar { 12 | top: 10px; 13 | bottom: 10px; 14 | transition: width 500ms; } } 15 | @media (min-width: 768px) and (max-width: 991px) { 16 | .sidebar { 17 | width: 305px; } } 18 | @media (min-width: 992px) and (max-width: 1199px) { 19 | .sidebar { 20 | width: 390px; } } 21 | @media (min-width: 1200px) { 22 | .sidebar { 23 | width: 460px; } } 24 | 25 | .sidebar-left { 26 | left: 0; } 27 | @media (min-width: 768px) { 28 | .sidebar-left { 29 | left: 10px; } } 30 | 31 | .sidebar-right { 32 | right: 0; } 33 | @media (min-width: 768px) { 34 | .sidebar-right { 35 | right: 10px; } } 36 | 37 | .sidebar-tabs { 38 | top: 0; 39 | bottom: 0; 40 | height: 100%; 41 | background-color: #fff; } 42 | .sidebar-left .sidebar-tabs { 43 | left: 0; } 44 | .sidebar-right .sidebar-tabs { 45 | right: 0; } 46 | .sidebar-tabs, .sidebar-tabs > ul { 47 | position: absolute; 48 | width: 40px; 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; } 52 | .sidebar-tabs > li, .sidebar-tabs > ul > li { 53 | width: 100%; 54 | height: 40px; 55 | color: #333; 56 | font-size: 12pt; 57 | overflow: hidden; 58 | transition: all 80ms; } 59 | .sidebar-tabs > li:hover, .sidebar-tabs > ul > li:hover { 60 | color: #000; 61 | background-color: #eee; } 62 | .sidebar-tabs > li.active, .sidebar-tabs > ul > li.active { 63 | color: #fff; 64 | background-color: #0074d9; } 65 | .sidebar-tabs > li.disabled, .sidebar-tabs > ul > li.disabled { 66 | color: rgba(51, 51, 51, 0.4); } 67 | .sidebar-tabs > li.disabled:hover, .sidebar-tabs > ul > li.disabled:hover { 68 | background: transparent; } 69 | .sidebar-tabs > li.disabled > a, .sidebar-tabs > ul > li.disabled > a { 70 | cursor: default; } 71 | .sidebar-tabs > li > a, .sidebar-tabs > ul > li > a { 72 | display: block; 73 | width: 100%; 74 | height: 100%; 75 | line-height: 40px; 76 | color: inherit; 77 | text-decoration: none; 78 | text-align: center; } 79 | .sidebar-tabs > ul + ul { 80 | bottom: 0; } 81 | 82 | .sidebar-content { 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | background-color: rgba(255, 255, 255, 0.95); 87 | overflow-x: hidden; 88 | overflow-y: auto; } 89 | .sidebar-left .sidebar-content { 90 | left: 40px; 91 | right: 0; } 92 | .sidebar-right .sidebar-content { 93 | left: 0; 94 | right: 40px; } 95 | .sidebar.collapsed > .sidebar-content { 96 | overflow-y: hidden; } 97 | 98 | .sidebar-pane { 99 | display: none; 100 | left: 0; 101 | right: 0; 102 | box-sizing: border-box; 103 | padding: 10px 20px; } 104 | .sidebar-pane.active { 105 | display: block; } 106 | @media (min-width: 768px) and (max-width: 991px) { 107 | .sidebar-pane { 108 | min-width: 265px; } } 109 | @media (min-width: 992px) and (max-width: 1199px) { 110 | .sidebar-pane { 111 | min-width: 350px; } } 112 | @media (min-width: 1200px) { 113 | .sidebar-pane { 114 | min-width: 420px; } } 115 | 116 | .sidebar-header { 117 | margin: -10px -20px 0; 118 | height: 40px; 119 | padding: 0 20px; 120 | line-height: 40px; 121 | font-size: 14.4pt; 122 | color: #fff; 123 | background-color: #0074d9; } 124 | .sidebar-right .sidebar-header { 125 | padding-left: 40px; } 126 | 127 | .sidebar-close { 128 | position: absolute; 129 | top: 0; 130 | width: 40px; 131 | height: 40px; 132 | text-align: center; 133 | cursor: pointer; } 134 | .sidebar-left .sidebar-close { 135 | right: 0; } 136 | .sidebar-right .sidebar-close { 137 | left: 0; } 138 | 139 | .sidebar-left ~ .sidebar-map { 140 | margin-left: 40px; } 141 | @media (min-width: 768px) { 142 | .sidebar-left ~ .sidebar-map { 143 | margin-left: 0; } } 144 | 145 | .sidebar-right ~ .sidebar-map { 146 | margin-right: 40px; } 147 | @media (min-width: 768px) { 148 | .sidebar-right ~ .sidebar-map { 149 | margin-right: 0; } } 150 | 151 | .sidebar { 152 | box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65); } 153 | .sidebar.leaflet-touch { 154 | box-shadow: none; 155 | border-right: 2px solid rgba(0, 0, 0, 0.2); } 156 | @media (min-width: 768px) { 157 | .sidebar { 158 | border-radius: 4px; } 159 | .sidebar.leaflet-touch { 160 | border: 2px solid rgba(0, 0, 0, 0.2); } } 161 | 162 | @media (min-width: 768px) { 163 | .sidebar-left ~ .sidebar-map .leaflet-left { 164 | transition: left 500ms; } } 165 | 166 | @media (min-width: 768px) and (max-width: 991px) { 167 | .sidebar-left ~ .sidebar-map .leaflet-left { 168 | left: 315px; } } 169 | 170 | @media (min-width: 992px) and (max-width: 1199px) { 171 | .sidebar-left ~ .sidebar-map .leaflet-left { 172 | left: 400px; } } 173 | 174 | @media (min-width: 1200px) { 175 | .sidebar-left ~ .sidebar-map .leaflet-left { 176 | left: 470px; } } 177 | 178 | @media (min-width: 768px) { 179 | .sidebar-left.collapsed ~ .sidebar-map .leaflet-left { 180 | left: 50px; } } 181 | 182 | @media (min-width: 768px) { 183 | .sidebar-right ~ .sidebar-map .leaflet-right { 184 | transition: right 500ms; } } 185 | 186 | @media (min-width: 768px) and (max-width: 991px) { 187 | .sidebar-right ~ .sidebar-map .leaflet-right { 188 | right: 315px; } } 189 | 190 | @media (min-width: 992px) and (max-width: 1199px) { 191 | .sidebar-right ~ .sidebar-map .leaflet-right { 192 | right: 400px; } } 193 | 194 | @media (min-width: 1200px) { 195 | .sidebar-right ~ .sidebar-map .leaflet-right { 196 | right: 470px; } } 197 | 198 | @media (min-width: 768px) { 199 | .sidebar-right.collapsed ~ .sidebar-map .leaflet-right { 200 | right: 50px; } } 201 | -------------------------------------------------------------------------------- /static/sidebar-v2/examples/gmaps.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sidebar-v2 example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 28 | 29 | 30 | 77 | 78 | 79 | 80 | Fork me on GitHub 81 | 82 | 83 | 84 | 85 | 86 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /static/sidebar-v2/scss/_base.scss: -------------------------------------------------------------------------------- 1 | $threshold-lg: 1200px !default; 2 | $threshold-md: 992px !default; 3 | $threshold-sm: 768px !default; 4 | 5 | $width-lg: 460px !default; 6 | $width-md: 390px !default; 7 | $width-sm: 305px !default; 8 | $width-xs: 100% !default; 9 | 10 | $sidebar-z-index: 2000 !default; 11 | $sidebar-transition: 500ms !default; 12 | 13 | $tab-size: 40px !default; 14 | $tab-font-size: 12pt !default; 15 | $tab-bg: null !default; 16 | $tab-transition: 80ms !default; 17 | 18 | $header-fg: $tab-active-fg !default; 19 | $header-bg: $tab-active-bg !default; 20 | 21 | $content-bg: rgba(255, 255, 255, 0.95) !default; 22 | $content-padding-vertical: 10px !default; 23 | $content-padding-horizontal: 20px !default; 24 | 25 | $move-map-in-xs: true !default; 26 | 27 | .sidebar { 28 | position: absolute; 29 | 30 | top: 0; 31 | bottom: 0; 32 | width: $width-xs; 33 | 34 | overflow: hidden; 35 | 36 | z-index: $sidebar-z-index; 37 | 38 | &.collapsed { 39 | width: $tab-size; 40 | } 41 | 42 | @media(min-width:$threshold-sm) { 43 | top: $sidebar-margins; 44 | bottom: $sidebar-margins; 45 | 46 | transition: width $sidebar-transition; 47 | } 48 | 49 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 50 | width: $width-sm; 51 | } 52 | 53 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 54 | width: $width-md; 55 | } 56 | 57 | @media(min-width:$threshold-lg) { 58 | width: $width-lg; 59 | } 60 | } 61 | 62 | .sidebar-left { 63 | left: 0; 64 | 65 | @media(min-width:$threshold-sm) { 66 | left: $sidebar-margins; 67 | } 68 | } 69 | 70 | .sidebar-right { 71 | right: 0; 72 | 73 | @media(min-width:$threshold-sm) { 74 | right: $sidebar-margins; 75 | } 76 | } 77 | 78 | .sidebar-tabs { 79 | top: 0; 80 | bottom: 0; 81 | height: 100%; 82 | 83 | .sidebar-left & { 84 | left: 0; 85 | } 86 | 87 | .sidebar-right & { 88 | right: 0; 89 | } 90 | 91 | background-color: $tabs-bg; 92 | 93 | &, & > ul { 94 | position: absolute; 95 | 96 | width: $tab-size; 97 | 98 | margin: 0; 99 | padding: 0; 100 | 101 | list-style-type: none; 102 | 103 | & > li { 104 | width: 100%; 105 | height: $tab-size; 106 | 107 | color: $tab-fg; 108 | @if $tab-bg { background: $tab-bg; } 109 | 110 | font-size: $tab-font-size; 111 | 112 | overflow: hidden; 113 | 114 | transition: all $tab-transition; 115 | 116 | &:hover { 117 | color: $tab-hover-fg; 118 | background-color: $tab-hover-bg; 119 | } 120 | 121 | &.active { 122 | color: $tab-active-fg; 123 | background-color: $tab-active-bg; 124 | } 125 | 126 | &.disabled { 127 | color: fade-out($tab-fg, 0.6); 128 | 129 | &:hover { 130 | @if $tab-bg { 131 | background: $tab-bg; 132 | } @else { 133 | background: transparent; 134 | } 135 | } 136 | 137 | & > a { 138 | cursor: default; 139 | } 140 | } 141 | 142 | & > a { 143 | display: block; 144 | 145 | width: 100%; 146 | height: 100%; 147 | 148 | line-height: $tab-size; 149 | 150 | color: inherit; 151 | text-decoration: none; 152 | text-align: center; 153 | } 154 | } 155 | } 156 | 157 | & > ul + ul { 158 | bottom: 0; 159 | } 160 | } 161 | 162 | .sidebar-content { 163 | position: absolute; 164 | 165 | .sidebar-left & { 166 | left: $tab-size; 167 | right: 0; 168 | } 169 | 170 | .sidebar-right & { 171 | left: 0; 172 | right: $tab-size; 173 | } 174 | 175 | top: 0; 176 | bottom: 0; 177 | 178 | background-color: $content-bg; 179 | 180 | overflow-x: hidden; 181 | overflow-y: auto; 182 | 183 | .sidebar.collapsed > & { 184 | overflow-y: hidden; 185 | } 186 | } 187 | 188 | .sidebar-pane { 189 | display: none; 190 | 191 | left: 0; 192 | right: 0; 193 | box-sizing: border-box; 194 | 195 | padding: $content-padding-vertical $content-padding-horizontal; 196 | 197 | &.active { 198 | display: block; 199 | } 200 | 201 | @media(min-width:$threshold-sm) and (max-width:$threshold-md - 1px) { 202 | min-width: $width-sm - $tab-size; 203 | } 204 | 205 | @media(min-width:$threshold-md) and (max-width:$threshold-lg - 1px) { 206 | min-width: $width-md - $tab-size; 207 | } 208 | 209 | @media(min-width:$threshold-lg) { 210 | min-width: $width-lg - $tab-size; 211 | } 212 | } 213 | 214 | .sidebar-header { 215 | margin: (-$content-padding-vertical) (-$content-padding-horizontal) 0; 216 | height: $tab-size; 217 | padding: 0 $content-padding-horizontal; 218 | line-height: $tab-size; 219 | font-size: $tab-font-size * 1.2; 220 | color: $header-fg; 221 | background-color: $header-bg; 222 | 223 | .sidebar-right & { 224 | padding-left: $tab-size; 225 | } 226 | } 227 | 228 | .sidebar-close { 229 | position: absolute; 230 | top: 0; 231 | width: $tab-size; 232 | height: $tab-size; 233 | text-align: center; 234 | cursor: pointer; 235 | 236 | .sidebar-left & { 237 | right: 0; 238 | } 239 | 240 | .sidebar-right & { 241 | left: 0; 242 | } 243 | } 244 | 245 | @if $move-map-in-xs { 246 | .sidebar-left ~ .sidebar-map { 247 | margin-left: $tab-size; 248 | 249 | @media(min-width:$threshold-sm) { 250 | margin-left: 0; 251 | } 252 | } 253 | 254 | .sidebar-right ~ .sidebar-map { 255 | margin-right: $tab-size; 256 | 257 | @media(min-width:$threshold-sm) { 258 | margin-right: 0; 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /static/sidebar-v2/examples/ol2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sidebar-v2 example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 29 | 30 | 31 | 78 | 79 | 80 | 81 | Fork me on GitHub 82 | 83 | 84 | 85 | 86 | 87 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /static/sidebar-v2/examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sidebar-v2 example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 30 | 31 | 32 | 79 | 80 | 81 | 82 | Fork me on GitHub 83 | 84 | 85 | 86 | 87 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /static/sidebar-v2/examples/position-right.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sidebar-v2 example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 30 | 31 | 32 | 79 | 80 | 81 | 82 | Fork me on GitHub 83 | 84 | 85 | 86 | 87 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /static/sidebar-v2/examples/ol3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sidebar-v2 example 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 30 | 31 | 32 | 79 | 80 | 81 | 82 | Fork me on GitHub 83 | 84 | 85 | 86 | 87 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /static/sidebar-v2/css/gmaps-sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | overflow: hidden; 7 | z-index: 2000; } 8 | .sidebar.collapsed { 9 | width: 40px; } 10 | @media (min-width: 768px) { 11 | .sidebar { 12 | top: 10px; 13 | bottom: 10px; 14 | transition: width 500ms; } } 15 | @media (min-width: 768px) and (max-width: 991px) { 16 | .sidebar { 17 | width: 305px; } } 18 | @media (min-width: 992px) and (max-width: 1199px) { 19 | .sidebar { 20 | width: 390px; } } 21 | @media (min-width: 1200px) { 22 | .sidebar { 23 | width: 460px; } } 24 | 25 | .sidebar-left { 26 | left: 0; } 27 | @media (min-width: 768px) { 28 | .sidebar-left { 29 | left: 10px; } } 30 | 31 | .sidebar-right { 32 | right: 0; } 33 | @media (min-width: 768px) { 34 | .sidebar-right { 35 | right: 10px; } } 36 | 37 | .sidebar-tabs { 38 | top: 0; 39 | bottom: 0; 40 | height: 100%; 41 | background-color: #fff; } 42 | .sidebar-left .sidebar-tabs { 43 | left: 0; } 44 | .sidebar-right .sidebar-tabs { 45 | right: 0; } 46 | .sidebar-tabs, .sidebar-tabs > ul { 47 | position: absolute; 48 | width: 40px; 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; } 52 | .sidebar-tabs > li, .sidebar-tabs > ul > li { 53 | width: 100%; 54 | height: 40px; 55 | color: #666; 56 | font-size: 12pt; 57 | overflow: hidden; 58 | transition: all 80ms; } 59 | .sidebar-tabs > li:hover, .sidebar-tabs > ul > li:hover { 60 | color: #000; 61 | background-color: #fff9e6; } 62 | .sidebar-tabs > li.active, .sidebar-tabs > ul > li.active { 63 | color: #000; 64 | background-color: #febf00; } 65 | .sidebar-tabs > li.disabled, .sidebar-tabs > ul > li.disabled { 66 | color: rgba(102, 102, 102, 0.4); } 67 | .sidebar-tabs > li.disabled:hover, .sidebar-tabs > ul > li.disabled:hover { 68 | background: transparent; } 69 | .sidebar-tabs > li.disabled > a, .sidebar-tabs > ul > li.disabled > a { 70 | cursor: default; } 71 | .sidebar-tabs > li > a, .sidebar-tabs > ul > li > a { 72 | display: block; 73 | width: 100%; 74 | height: 100%; 75 | line-height: 40px; 76 | color: inherit; 77 | text-decoration: none; 78 | text-align: center; } 79 | .sidebar-tabs > ul + ul { 80 | bottom: 0; } 81 | 82 | .sidebar-content { 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | background-color: rgba(255, 255, 255, 0.95); 87 | overflow-x: hidden; 88 | overflow-y: auto; } 89 | .sidebar-left .sidebar-content { 90 | left: 40px; 91 | right: 0; } 92 | .sidebar-right .sidebar-content { 93 | left: 0; 94 | right: 40px; } 95 | .sidebar.collapsed > .sidebar-content { 96 | overflow-y: hidden; } 97 | 98 | .sidebar-pane { 99 | display: none; 100 | left: 0; 101 | right: 0; 102 | box-sizing: border-box; 103 | padding: 10px 20px; } 104 | .sidebar-pane.active { 105 | display: block; } 106 | @media (min-width: 768px) and (max-width: 991px) { 107 | .sidebar-pane { 108 | min-width: 265px; } } 109 | @media (min-width: 992px) and (max-width: 1199px) { 110 | .sidebar-pane { 111 | min-width: 350px; } } 112 | @media (min-width: 1200px) { 113 | .sidebar-pane { 114 | min-width: 420px; } } 115 | 116 | .sidebar-header { 117 | margin: -10px -20px 0; 118 | height: 40px; 119 | padding: 0 20px; 120 | line-height: 40px; 121 | font-size: 14.4pt; 122 | color: #000; 123 | background-color: #febf00; } 124 | .sidebar-right .sidebar-header { 125 | padding-left: 40px; } 126 | 127 | .sidebar-close { 128 | position: absolute; 129 | top: 0; 130 | width: 40px; 131 | height: 40px; 132 | text-align: center; 133 | cursor: pointer; } 134 | .sidebar-left .sidebar-close { 135 | right: 0; } 136 | .sidebar-right .sidebar-close { 137 | left: 0; } 138 | 139 | .sidebar-left ~ .sidebar-map { 140 | margin-left: 40px; } 141 | @media (min-width: 768px) { 142 | .sidebar-left ~ .sidebar-map { 143 | margin-left: 0; } } 144 | 145 | .sidebar-right ~ .sidebar-map { 146 | margin-right: 40px; } 147 | @media (min-width: 768px) { 148 | .sidebar-right ~ .sidebar-map { 149 | margin-right: 0; } } 150 | 151 | .sidebar { 152 | border-right: 0; 153 | box-shadow: rgba(0, 0, 0, 0.298039) 0 1px 4px -1px; } 154 | @media (min-width: 768px) { 155 | .sidebar { 156 | border: 0; 157 | border-radius: 2px; } } 158 | 159 | @media (min-width: 768px) { 160 | .sidebar-left { 161 | bottom: 35px; } } 162 | 163 | @media (min-width: 768px) { 164 | .sidebar-left ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 165 | transition: margin-left 500ms; } } 166 | 167 | @media (min-width: 768px) and (max-width: 991px) { 168 | .sidebar-left ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 169 | margin-left: 325px !important; } } 170 | 171 | @media (min-width: 992px) and (max-width: 1199px) { 172 | .sidebar-left ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 173 | margin-left: 410px !important; } } 174 | 175 | @media (min-width: 1200px) { 176 | .sidebar-left ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 177 | margin-left: 480px !important; } } 178 | 179 | @media (min-width: 768px) { 180 | .sidebar-left.collapsed ~ .sidebar-map .gm-style > div.gmnoprint[style*="left: 0px"] { 181 | margin-left: 60px !important; } } 182 | 183 | @media (min-width: 768px) { 184 | .sidebar-right { 185 | bottom: 24px; } } 186 | 187 | @media (min-width: 768px) { 188 | .sidebar-right ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 189 | transition: margin-right 500ms; } } 190 | 191 | @media (min-width: 768px) and (max-width: 991px) { 192 | .sidebar-right ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 193 | margin-right: 325px !important; } } 194 | 195 | @media (min-width: 992px) and (max-width: 1199px) { 196 | .sidebar-right ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 197 | margin-right: 410px !important; } } 198 | 199 | @media (min-width: 1200px) { 200 | .sidebar-right ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 201 | margin-right: 480px !important; } } 202 | 203 | @media (min-width: 768px) { 204 | .sidebar-right.collapsed ~ .sidebar-map .gm-style > div.gmnoprint[style*="right: 28px"] { 205 | margin-right: 60px !important; } } 206 | -------------------------------------------------------------------------------- /static/sidebar-v2/css/ol3-sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | overflow: hidden; 7 | z-index: 2000; } 8 | .sidebar.collapsed { 9 | width: 40px; } 10 | @media (min-width: 768px) { 11 | .sidebar { 12 | top: 6px; 13 | bottom: 6px; 14 | transition: width 500ms; } } 15 | @media (min-width: 768px) and (max-width: 991px) { 16 | .sidebar { 17 | width: 305px; } } 18 | @media (min-width: 992px) and (max-width: 1199px) { 19 | .sidebar { 20 | width: 390px; } } 21 | @media (min-width: 1200px) { 22 | .sidebar { 23 | width: 460px; } } 24 | 25 | .sidebar-left { 26 | left: 0; } 27 | @media (min-width: 768px) { 28 | .sidebar-left { 29 | left: 6px; } } 30 | 31 | .sidebar-right { 32 | right: 0; } 33 | @media (min-width: 768px) { 34 | .sidebar-right { 35 | right: 6px; } } 36 | 37 | .sidebar-tabs { 38 | top: 0; 39 | bottom: 0; 40 | height: 100%; 41 | background-color: rgba(0, 60, 136, 0.5); } 42 | .sidebar-left .sidebar-tabs { 43 | left: 0; } 44 | .sidebar-right .sidebar-tabs { 45 | right: 0; } 46 | .sidebar-tabs, .sidebar-tabs > ul { 47 | position: absolute; 48 | width: 40px; 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; } 52 | .sidebar-tabs > li, .sidebar-tabs > ul > li { 53 | width: 100%; 54 | height: 40px; 55 | color: #fff; 56 | font-size: 12pt; 57 | overflow: hidden; 58 | transition: all 80ms; } 59 | .sidebar-tabs > li:hover, .sidebar-tabs > ul > li:hover { 60 | color: #fff; 61 | background-color: rgba(0, 60, 136, 0.6); } 62 | .sidebar-tabs > li.active, .sidebar-tabs > ul > li.active { 63 | color: #fff; 64 | background-color: #0074d9; } 65 | .sidebar-tabs > li.disabled, .sidebar-tabs > ul > li.disabled { 66 | color: rgba(255, 255, 255, 0.4); } 67 | .sidebar-tabs > li.disabled:hover, .sidebar-tabs > ul > li.disabled:hover { 68 | background: transparent; } 69 | .sidebar-tabs > li.disabled > a, .sidebar-tabs > ul > li.disabled > a { 70 | cursor: default; } 71 | .sidebar-tabs > li > a, .sidebar-tabs > ul > li > a { 72 | display: block; 73 | width: 100%; 74 | height: 100%; 75 | line-height: 40px; 76 | color: inherit; 77 | text-decoration: none; 78 | text-align: center; } 79 | .sidebar-tabs > ul + ul { 80 | bottom: 0; } 81 | 82 | .sidebar-content { 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | background-color: rgba(255, 255, 255, 0.95); 87 | overflow-x: hidden; 88 | overflow-y: auto; } 89 | .sidebar-left .sidebar-content { 90 | left: 40px; 91 | right: 0; } 92 | .sidebar-right .sidebar-content { 93 | left: 0; 94 | right: 40px; } 95 | .sidebar.collapsed > .sidebar-content { 96 | overflow-y: hidden; } 97 | 98 | .sidebar-pane { 99 | display: none; 100 | left: 0; 101 | right: 0; 102 | box-sizing: border-box; 103 | padding: 10px 20px; } 104 | .sidebar-pane.active { 105 | display: block; } 106 | @media (min-width: 768px) and (max-width: 991px) { 107 | .sidebar-pane { 108 | min-width: 265px; } } 109 | @media (min-width: 992px) and (max-width: 1199px) { 110 | .sidebar-pane { 111 | min-width: 350px; } } 112 | @media (min-width: 1200px) { 113 | .sidebar-pane { 114 | min-width: 420px; } } 115 | 116 | .sidebar-header { 117 | margin: -10px -20px 0; 118 | height: 40px; 119 | padding: 0 20px; 120 | line-height: 40px; 121 | font-size: 14.4pt; 122 | color: #fff; 123 | background-color: #0074d9; } 124 | .sidebar-right .sidebar-header { 125 | padding-left: 40px; } 126 | 127 | .sidebar-close { 128 | position: absolute; 129 | top: 0; 130 | width: 40px; 131 | height: 40px; 132 | text-align: center; 133 | cursor: pointer; } 134 | .sidebar-left .sidebar-close { 135 | right: 0; } 136 | .sidebar-right .sidebar-close { 137 | left: 0; } 138 | 139 | .sidebar { 140 | background-color: rgba(255, 255, 255, 0.4); } 141 | @media (min-width: 768px) { 142 | .sidebar { 143 | border: 3px solid transparent; 144 | border-radius: 4px; } } 145 | 146 | .sidebar-left { 147 | border-right: 3px solid transparent; } 148 | 149 | .sidebar-right { 150 | border-left: 3px solid transparent; } 151 | 152 | .sidebar-tabs { 153 | overflow: hidden; } 154 | @media (min-width: 768px) { 155 | .sidebar-tabs { 156 | border-radius: 2px 0 0 2px; } 157 | .collapsed .sidebar-tabs { 158 | border-radius: 2px; } } 159 | 160 | @media (min-width: 768px) { 161 | .sidebar-content { 162 | border-radius: 0 2px 2px 0; } } 163 | 164 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 165 | margin-left: 46px; } 166 | @media (min-width: 768px) { 167 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 168 | transition: margin-left 500ms; } } 169 | @media (min-width: 768px) and (max-width: 991px) { 170 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 171 | margin-left: 317px; } } 172 | @media (min-width: 992px) and (max-width: 1199px) { 173 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 174 | margin-left: 402px; } } 175 | @media (min-width: 1200px) { 176 | .sidebar-left ~ .sidebar-map .ol-zoom, .sidebar-left ~ .sidebar-map .ol-scale-line { 177 | margin-left: 472px; } } 178 | 179 | @media (min-width: 768px) { 180 | .sidebar-left.collapsed ~ .sidebar-map .ol-zoom, .sidebar-left.collapsed ~ .sidebar-map .ol-scale-line { 181 | margin-left: 52px; } } 182 | 183 | .sidebar-right ~ .sidebar-map .ol-rotate, 184 | .sidebar-right ~ .sidebar-map .ol-attribution, 185 | .sidebar-right ~ .sidebar-map .ol-full-screen { 186 | margin-right: 46px; } 187 | @media (min-width: 768px) { 188 | .sidebar-right ~ .sidebar-map .ol-rotate, 189 | .sidebar-right ~ .sidebar-map .ol-attribution, 190 | .sidebar-right ~ .sidebar-map .ol-full-screen { 191 | transition: margin-right 500ms; } } 192 | @media (min-width: 768px) and (max-width: 991px) { 193 | .sidebar-right ~ .sidebar-map .ol-rotate, 194 | .sidebar-right ~ .sidebar-map .ol-attribution, 195 | .sidebar-right ~ .sidebar-map .ol-full-screen { 196 | margin-right: 317px; } } 197 | @media (min-width: 992px) and (max-width: 1199px) { 198 | .sidebar-right ~ .sidebar-map .ol-rotate, 199 | .sidebar-right ~ .sidebar-map .ol-attribution, 200 | .sidebar-right ~ .sidebar-map .ol-full-screen { 201 | margin-right: 402px; } } 202 | @media (min-width: 1200px) { 203 | .sidebar-right ~ .sidebar-map .ol-rotate, 204 | .sidebar-right ~ .sidebar-map .ol-attribution, 205 | .sidebar-right ~ .sidebar-map .ol-full-screen { 206 | margin-right: 472px; } } 207 | 208 | @media (min-width: 768px) { 209 | .sidebar-right.collapsed ~ .sidebar-map .ol-rotate, 210 | .sidebar-right.collapsed ~ .sidebar-map .ol-attribution, 211 | .sidebar-right.collapsed ~ .sidebar-map .ol-full-screen { 212 | margin-right: 52px; } } 213 | -------------------------------------------------------------------------------- /pa8.py: -------------------------------------------------------------------------------- 1 | """PLA Pokemon Format""" 2 | class ByteStruct: 3 | """Object to represent a structure of bytes""" 4 | def __init__(self,buf): 5 | self.data = bytearray(buf[:]) 6 | 7 | def get_ulong(self,offset): 8 | """Pull u64 from bytes""" 9 | return int.from_bytes(self.data[offset:offset + 8], byteorder='little') 10 | 11 | def get_uint(self,offset): 12 | """Pull u32 from bytes""" 13 | return int.from_bytes(self.data[offset:offset + 4], byteorder='little') 14 | 15 | def get_ushort(self,offset): 16 | """Pull u16 from bytes""" 17 | return int.from_bytes(self.data[offset:offset + 2], byteorder='little') 18 | 19 | def get_byte(self,offset): 20 | """Pull u8 from bytes""" 21 | return self.data[offset] 22 | 23 | class Pa8(ByteStruct): 24 | """PLA Pokemon Format""" 25 | # pylint: disable=too-many-public-methods 26 | # pkxs contain a lot of information that may need to be accessed 27 | STOREDSIZE = 360 28 | BLOCKSIZE = 88 29 | 30 | def __init__(self,buf): 31 | ByteStruct.__init__(self,buf) 32 | if self.is_encrypted: 33 | self.decrypt() 34 | 35 | @property 36 | def encryption_constant(self): 37 | """Pokemon's EC""" 38 | return self.get_uint(0x0) 39 | 40 | @property 41 | def checksum(self): 42 | """Pokemon's checksum""" 43 | return self.get_ushort(0x6) 44 | 45 | @property 46 | def species(self): 47 | """Pokemon's species""" 48 | return self.get_ushort(0x8) 49 | 50 | @property 51 | def sidtid(self): 52 | """Pokemon's sidtid""" 53 | return self.get_uint(0x0C) 54 | 55 | @property 56 | def ability(self): 57 | """Pokemon's ability index""" 58 | return self.get_ushort(0x14) 59 | 60 | @property 61 | def ability_num(self): 62 | """Pokemon's species-specific ability index""" 63 | return self.get_byte(0x16) & 0x7 64 | 65 | @property 66 | def ability_string(self): 67 | """Pokemon's species-specific ability string""" 68 | return self.ability_num if self.ability_num < 4 else 'H' 69 | 70 | @property 71 | def pid(self): 72 | """Pokemon's PID""" 73 | return self.get_uint(0x1C) 74 | 75 | @property 76 | def nature(self): 77 | """Pokemon's nature""" 78 | return self.get_byte(0x20) 79 | 80 | @property 81 | def gender(self): 82 | """Pokemon's gender""" 83 | return (self.get_byte(0x22) >> 2) & 0x3 84 | 85 | @property 86 | def form_index(self): 87 | """Pokemon's form index""" 88 | return self.get_ushort(0x24) 89 | 90 | @property 91 | def evs(self): 92 | """Pokemon's EVs""" 93 | return [self.data[0x26], 94 | self.data[0x27], 95 | self.data[0x28], 96 | self.data[0x2A], 97 | self.data[0x2B], 98 | self.data[0x29]] 99 | 100 | @property 101 | def move1(self): 102 | """Pokemon's first move""" 103 | return self.get_ushort(0x54) 104 | 105 | @property 106 | def move2(self): 107 | """Pokemon's second move""" 108 | return self.get_ushort(0x56) 109 | 110 | @property 111 | def move3(self): 112 | """Pokemon's third move""" 113 | return self.get_ushort(0x58) 114 | 115 | @property 116 | def move4(self): 117 | """Pokemon's fourth move""" 118 | return self.get_ushort(0x5A) 119 | 120 | @property 121 | def iv32(self): 122 | """Pokemon's ivs as a u32""" 123 | return self.get_uint(0x94) 124 | 125 | @property 126 | def ivs(self): 127 | """Pokemon's ivs""" 128 | iv32 = self.iv32 129 | return [iv32 & 0x1F, 130 | (iv32 >> 5) & 0x1F, 131 | (iv32 >> 10) & 0x1F, 132 | (iv32 >> 20) & 0x1F, 133 | (iv32 >> 25) & 0x1F, 134 | (iv32 >> 15) & 0x1F] 135 | 136 | def calc_checksum(self): 137 | """Calculate the pokemons checksum for data validation""" 138 | chk = 0 139 | for i in range(8,Pa8.STOREDSIZE,2): 140 | chk += self.get_ushort(i) 141 | chk &= 0xFFFF 142 | return chk 143 | 144 | @property 145 | def shiny_type(self): 146 | """Shiny type of a pokemon""" 147 | xor = (self.sidtid >> 16) ^ (self.sidtid & 0xFFFF) ^ (self.pid >> 16) ^ (self.pid & 0xFFFF) 148 | if xor > 15: 149 | return 0 150 | return 2 if xor == 0 else 1 151 | 152 | @property 153 | def shiny_string(self): 154 | """Shiny type of a pokemon as a string""" 155 | return 'None' if self.shiny_type == 0 else 'Star' if self.shiny_type == 1 else 'Square' 156 | 157 | @property 158 | def is_valid(self): 159 | """Check the validity of a pokemon""" 160 | return self.checksum == self.calc_checksum() and not self.is_encrypted 161 | 162 | @property 163 | def is_encrypted(self): 164 | """Check if the pokemon is encrypted""" 165 | return self.get_ushort(0x70) != 0 and self.get_ushort(0xC0) != 0 166 | 167 | def decrypt(self): 168 | """Decrypt an ea8""" 169 | seed = self.encryption_constant 170 | shuffle_order = (seed >> 13) & 0x1F 171 | 172 | self.__crypt_pkm__(seed) 173 | self.__shuffle__(shuffle_order) 174 | 175 | def __crypt_pkm__(self,seed): 176 | """Run __crypt__ specific to the pokemon size""" 177 | self.__crypt__(seed, 8, Pa8.STOREDSIZE) 178 | 179 | def __crypt__(self, seed, start, end): 180 | """Encrypt/decrypt a based on seed""" 181 | i = start 182 | while i < end: 183 | seed = seed * 0x41C64E6D + 0x6073 184 | self.data[i] ^= (seed >> 16) & 0xFF 185 | i += 1 186 | self.data[i] ^= (seed >> 24) & 0xFF 187 | i += 1 188 | 189 | def __shuffle__(self, shuffle_order): 190 | """Shuffle the bytes""" 191 | idx = 4 * shuffle_order 192 | sdata = bytearray(self.data[:]) 193 | for block in range(4): 194 | ofs = Pa8.BLOCKPOSITION[idx + block] 195 | self.data[8 + Pa8.BLOCKSIZE * block : 8 + Pa8.BLOCKSIZE * (block + 1)] \ 196 | = sdata[8 + Pa8.BLOCKSIZE * ofs : 8 + Pa8.BLOCKSIZE * (ofs + 1)] 197 | 198 | BLOCKPOSITION = [ 199 | 0, 1, 2, 3, 200 | 0, 1, 3, 2, 201 | 0, 2, 1, 3, 202 | 0, 3, 1, 2, 203 | 0, 2, 3, 1, 204 | 0, 3, 2, 1, 205 | 1, 0, 2, 3, 206 | 1, 0, 3, 2, 207 | 2, 0, 1, 3, 208 | 3, 0, 1, 2, 209 | 2, 0, 3, 1, 210 | 3, 0, 2, 1, 211 | 1, 2, 0, 3, 212 | 1, 3, 0, 2, 213 | 2, 1, 0, 3, 214 | 3, 1, 0, 2, 215 | 2, 3, 0, 1, 216 | 3, 2, 0, 1, 217 | 1, 2, 3, 0, 218 | 1, 3, 2, 0, 219 | 2, 1, 3, 0, 220 | 3, 1, 2, 0, 221 | 2, 3, 1, 0, 222 | 3, 2, 1, 0, 223 | 224 | # duplicates of 0-7 to eliminate modulus 225 | 0, 1, 2, 3, 226 | 0, 1, 3, 2, 227 | 0, 2, 1, 3, 228 | 0, 3, 1, 2, 229 | 0, 2, 3, 1, 230 | 0, 3, 2, 1, 231 | 1, 0, 2, 3, 232 | 1, 0, 3, 2, 233 | ] 234 | -------------------------------------------------------------------------------- /static/sidebar-v2/css/ol2-sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | overflow: hidden; 7 | z-index: 2000; } 8 | .sidebar.collapsed { 9 | width: 40px; } 10 | @media (min-width: 768px) { 11 | .sidebar { 12 | top: 8px; 13 | bottom: 8px; 14 | transition: width 500ms; } } 15 | @media (min-width: 768px) and (max-width: 991px) { 16 | .sidebar { 17 | width: 305px; } } 18 | @media (min-width: 992px) and (max-width: 1199px) { 19 | .sidebar { 20 | width: 390px; } } 21 | @media (min-width: 1200px) { 22 | .sidebar { 23 | width: 460px; } } 24 | 25 | .sidebar-left { 26 | left: 0; } 27 | @media (min-width: 768px) { 28 | .sidebar-left { 29 | left: 8px; } } 30 | 31 | .sidebar-right { 32 | right: 0; } 33 | @media (min-width: 768px) { 34 | .sidebar-right { 35 | right: 8px; } } 36 | 37 | .sidebar-tabs { 38 | top: 0; 39 | bottom: 0; 40 | height: 100%; 41 | background-color: rgba(0, 60, 136, 0.5); } 42 | .sidebar-left .sidebar-tabs { 43 | left: 0; } 44 | .sidebar-right .sidebar-tabs { 45 | right: 0; } 46 | .sidebar-tabs, .sidebar-tabs > ul { 47 | position: absolute; 48 | width: 40px; 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; } 52 | .sidebar-tabs > li, .sidebar-tabs > ul > li { 53 | width: 100%; 54 | height: 40px; 55 | color: #fff; 56 | font-size: 12pt; 57 | overflow: hidden; 58 | transition: all 80ms; } 59 | .sidebar-tabs > li:hover, .sidebar-tabs > ul > li:hover { 60 | color: #fff; 61 | background-color: rgba(0, 60, 136, 0.6); } 62 | .sidebar-tabs > li.active, .sidebar-tabs > ul > li.active { 63 | color: #fff; 64 | background-color: #0074d9; } 65 | .sidebar-tabs > li.disabled, .sidebar-tabs > ul > li.disabled { 66 | color: rgba(255, 255, 255, 0.4); } 67 | .sidebar-tabs > li.disabled:hover, .sidebar-tabs > ul > li.disabled:hover { 68 | background: transparent; } 69 | .sidebar-tabs > li.disabled > a, .sidebar-tabs > ul > li.disabled > a { 70 | cursor: default; } 71 | .sidebar-tabs > li > a, .sidebar-tabs > ul > li > a { 72 | display: block; 73 | width: 100%; 74 | height: 100%; 75 | line-height: 40px; 76 | color: inherit; 77 | text-decoration: none; 78 | text-align: center; } 79 | .sidebar-tabs > ul + ul { 80 | bottom: 0; } 81 | 82 | .sidebar-content { 83 | position: absolute; 84 | top: 0; 85 | bottom: 0; 86 | background-color: rgba(255, 255, 255, 0.95); 87 | overflow-x: hidden; 88 | overflow-y: auto; } 89 | .sidebar-left .sidebar-content { 90 | left: 40px; 91 | right: 0; } 92 | .sidebar-right .sidebar-content { 93 | left: 0; 94 | right: 40px; } 95 | .sidebar.collapsed > .sidebar-content { 96 | overflow-y: hidden; } 97 | 98 | .sidebar-pane { 99 | display: none; 100 | left: 0; 101 | right: 0; 102 | box-sizing: border-box; 103 | padding: 10px 20px; } 104 | .sidebar-pane.active { 105 | display: block; } 106 | @media (min-width: 768px) and (max-width: 991px) { 107 | .sidebar-pane { 108 | min-width: 265px; } } 109 | @media (min-width: 992px) and (max-width: 1199px) { 110 | .sidebar-pane { 111 | min-width: 350px; } } 112 | @media (min-width: 1200px) { 113 | .sidebar-pane { 114 | min-width: 420px; } } 115 | 116 | .sidebar-header { 117 | margin: -10px -20px 0; 118 | height: 40px; 119 | padding: 0 20px; 120 | line-height: 40px; 121 | font-size: 14.4pt; 122 | color: #fff; 123 | background-color: #0074d9; } 124 | .sidebar-right .sidebar-header { 125 | padding-left: 40px; } 126 | 127 | .sidebar-close { 128 | position: absolute; 129 | top: 0; 130 | width: 40px; 131 | height: 40px; 132 | text-align: center; 133 | cursor: pointer; } 134 | .sidebar-left .sidebar-close { 135 | right: 0; } 136 | .sidebar-right .sidebar-close { 137 | left: 0; } 138 | 139 | .sidebar { 140 | background-color: rgba(255, 255, 255, 0.4); } 141 | @media (min-width: 768px) { 142 | .sidebar { 143 | border: 3px solid transparent; 144 | border-radius: 4px; } } 145 | 146 | .sidebar-left { 147 | border-right: 3px solid transparent; } 148 | 149 | .sidebar-right { 150 | border-left: 3px solid transparent; } 151 | 152 | .sidebar-tabs { 153 | overflow: hidden; } 154 | @media (min-width: 768px) { 155 | .sidebar-tabs { 156 | border-radius: 4px 0 0 4px; } 157 | .collapsed .sidebar-tabs { 158 | border-radius: 4px; } } 159 | 160 | @media (min-width: 768px) { 161 | .sidebar-content { 162 | border-radius: 0 4px 4px 0; } } 163 | 164 | .sidebar-left ~ .sidebar-map .olControlZoom, 165 | .sidebar-left ~ .sidebar-map .olScaleLine { 166 | margin-left: 46px; } 167 | @media (min-width: 768px) { 168 | .sidebar-left ~ .sidebar-map .olControlZoom, 169 | .sidebar-left ~ .sidebar-map .olScaleLine { 170 | transition: margin-left 500ms; } } 171 | @media (min-width: 768px) and (max-width: 991px) { 172 | .sidebar-left ~ .sidebar-map .olControlZoom, 173 | .sidebar-left ~ .sidebar-map .olScaleLine { 174 | margin-left: 319px; } } 175 | @media (min-width: 992px) and (max-width: 1199px) { 176 | .sidebar-left ~ .sidebar-map .olControlZoom, 177 | .sidebar-left ~ .sidebar-map .olScaleLine { 178 | margin-left: 404px; } } 179 | @media (min-width: 1200px) { 180 | .sidebar-left ~ .sidebar-map .olControlZoom, 181 | .sidebar-left ~ .sidebar-map .olScaleLine { 182 | margin-left: 474px; } } 183 | 184 | @media (min-width: 768px) { 185 | .sidebar-left.collapsed ~ .sidebar-map .olControlZoom, 186 | .sidebar-left.collapsed ~ .sidebar-map .olScaleLine { 187 | margin-left: 54px; } } 188 | 189 | .sidebar-right ~ .sidebar-map .olControlAttribution, 190 | .sidebar-right ~ .sidebar-map .olControlPermalink, 191 | .sidebar-right ~ .sidebar-map .olControlMousePosition { 192 | margin-right: 46px; } 193 | @media (min-width: 768px) { 194 | .sidebar-right ~ .sidebar-map .olControlAttribution, 195 | .sidebar-right ~ .sidebar-map .olControlPermalink, 196 | .sidebar-right ~ .sidebar-map .olControlMousePosition { 197 | transition: margin-right 500ms; } } 198 | @media (min-width: 768px) and (max-width: 991px) { 199 | .sidebar-right ~ .sidebar-map .olControlAttribution, 200 | .sidebar-right ~ .sidebar-map .olControlPermalink, 201 | .sidebar-right ~ .sidebar-map .olControlMousePosition { 202 | margin-right: 319px; } } 203 | @media (min-width: 992px) and (max-width: 1199px) { 204 | .sidebar-right ~ .sidebar-map .olControlAttribution, 205 | .sidebar-right ~ .sidebar-map .olControlPermalink, 206 | .sidebar-right ~ .sidebar-map .olControlMousePosition { 207 | margin-right: 404px; } } 208 | @media (min-width: 1200px) { 209 | .sidebar-right ~ .sidebar-map .olControlAttribution, 210 | .sidebar-right ~ .sidebar-map .olControlPermalink, 211 | .sidebar-right ~ .sidebar-map .olControlMousePosition { 212 | margin-right: 474px; } } 213 | 214 | @media (min-width: 768px) { 215 | .sidebar-right.collapsed ~ .sidebar-map .olControlAttribution, 216 | .sidebar-right.collapsed ~ .sidebar-map .olControlPermalink, 217 | .sidebar-right.collapsed ~ .sidebar-map .olControlMousePosition { 218 | margin-right: 54px; } } 219 | -------------------------------------------------------------------------------- /static/sidebar-v2/js/leaflet-sidebar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Sidebar 3 | * @class L.Control.Sidebar 4 | * @extends L.Control 5 | * @param {string} id - The id of the sidebar element (without the # character) 6 | * @param {Object} [options] - Optional options object 7 | * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right' 8 | * @see L.control.sidebar 9 | */ 10 | L.Control.Sidebar = L.Control.extend(/** @lends L.Control.Sidebar.prototype */ { 11 | includes: (L.Evented.prototype || L.Mixin.Events), 12 | 13 | options: { 14 | position: 'left' 15 | }, 16 | 17 | initialize: function (id, options) { 18 | var i, child; 19 | 20 | L.setOptions(this, options); 21 | 22 | // Find sidebar HTMLElement 23 | this._sidebar = L.DomUtil.get(id); 24 | 25 | // Attach .sidebar-left/right class 26 | L.DomUtil.addClass(this._sidebar, 'sidebar-' + this.options.position); 27 | 28 | // Attach touch styling if necessary 29 | if (L.Browser.touch) 30 | L.DomUtil.addClass(this._sidebar, 'leaflet-touch'); 31 | 32 | // Find sidebar > div.sidebar-content 33 | for (i = this._sidebar.children.length - 1; i >= 0; i--) { 34 | child = this._sidebar.children[i]; 35 | if (child.tagName == 'DIV' && 36 | L.DomUtil.hasClass(child, 'sidebar-content')) 37 | this._container = child; 38 | } 39 | 40 | // Find sidebar ul.sidebar-tabs > li, sidebar .sidebar-tabs > ul > li 41 | this._tabitems = this._sidebar.querySelectorAll('ul.sidebar-tabs > li, .sidebar-tabs > ul > li'); 42 | for (i = this._tabitems.length - 1; i >= 0; i--) { 43 | this._tabitems[i]._sidebar = this; 44 | } 45 | 46 | // Find sidebar > div.sidebar-content > div.sidebar-pane 47 | this._panes = []; 48 | this._closeButtons = []; 49 | for (i = this._container.children.length - 1; i >= 0; i--) { 50 | child = this._container.children[i]; 51 | if (child.tagName == 'DIV' && 52 | L.DomUtil.hasClass(child, 'sidebar-pane')) { 53 | this._panes.push(child); 54 | 55 | var closeButtons = child.querySelectorAll('.sidebar-close'); 56 | for (var j = 0, len = closeButtons.length; j < len; j++) 57 | this._closeButtons.push(closeButtons[j]); 58 | } 59 | } 60 | }, 61 | 62 | /** 63 | * Add this sidebar to the specified map. 64 | * 65 | * @param {L.Map} map 66 | * @returns {Sidebar} 67 | */ 68 | addTo: function (map) { 69 | var i, child; 70 | 71 | this._map = map; 72 | 73 | for (i = this._tabitems.length - 1; i >= 0; i--) { 74 | child = this._tabitems[i]; 75 | var sub = child.querySelector('a'); 76 | if (sub.hasAttribute('href') && sub.getAttribute('href').slice(0,1) == '#') { 77 | L.DomEvent 78 | .on(sub, 'click', L.DomEvent.preventDefault ) 79 | .on(sub, 'click', this._onClick, child); 80 | } 81 | } 82 | 83 | for (i = this._closeButtons.length - 1; i >= 0; i--) { 84 | child = this._closeButtons[i]; 85 | L.DomEvent.on(child, 'click', this._onCloseClick, this); 86 | } 87 | 88 | return this; 89 | }, 90 | 91 | /** 92 | * @deprecated - Please use remove() instead of removeFrom(), as of Leaflet 0.8-dev, the removeFrom() has been replaced with remove() 93 | * Removes this sidebar from the map. 94 | * @param {L.Map} map 95 | * @returns {Sidebar} 96 | */ 97 | removeFrom: function(map) { 98 | console.log('removeFrom() has been deprecated, please use remove() instead as support for this function will be ending soon.'); 99 | this.remove(map); 100 | }, 101 | 102 | /** 103 | * Remove this sidebar from the map. 104 | * 105 | * @param {L.Map} map 106 | * @returns {Sidebar} 107 | */ 108 | remove: function (map) { 109 | var i, child; 110 | 111 | this._map = null; 112 | 113 | for (i = this._tabitems.length - 1; i >= 0; i--) { 114 | child = this._tabitems[i]; 115 | L.DomEvent.off(child.querySelector('a'), 'click', this._onClick); 116 | } 117 | 118 | for (i = this._closeButtons.length - 1; i >= 0; i--) { 119 | child = this._closeButtons[i]; 120 | L.DomEvent.off(child, 'click', this._onCloseClick, this); 121 | } 122 | 123 | return this; 124 | }, 125 | 126 | /** 127 | * Open sidebar (if necessary) and show the specified tab. 128 | * 129 | * @param {string} id - The id of the tab to show (without the # character) 130 | */ 131 | open: function(id) { 132 | var i, child; 133 | 134 | // hide old active contents and show new content 135 | for (i = this._panes.length - 1; i >= 0; i--) { 136 | child = this._panes[i]; 137 | if (child.id == id) 138 | L.DomUtil.addClass(child, 'active'); 139 | else if (L.DomUtil.hasClass(child, 'active')) 140 | L.DomUtil.removeClass(child, 'active'); 141 | } 142 | 143 | // remove old active highlights and set new highlight 144 | for (i = this._tabitems.length - 1; i >= 0; i--) { 145 | child = this._tabitems[i]; 146 | if (child.querySelector('a').hash == '#' + id) 147 | L.DomUtil.addClass(child, 'active'); 148 | else if (L.DomUtil.hasClass(child, 'active')) 149 | L.DomUtil.removeClass(child, 'active'); 150 | } 151 | 152 | this.fire('content', { id: id }); 153 | 154 | // open sidebar (if necessary) 155 | if (L.DomUtil.hasClass(this._sidebar, 'collapsed')) { 156 | this.fire('opening'); 157 | L.DomUtil.removeClass(this._sidebar, 'collapsed'); 158 | } 159 | 160 | return this; 161 | }, 162 | 163 | /** 164 | * Close the sidebar (if necessary). 165 | */ 166 | close: function() { 167 | // remove old active highlights 168 | for (var i = this._tabitems.length - 1; i >= 0; i--) { 169 | var child = this._tabitems[i]; 170 | if (L.DomUtil.hasClass(child, 'active')) 171 | L.DomUtil.removeClass(child, 'active'); 172 | } 173 | 174 | // close sidebar 175 | if (!L.DomUtil.hasClass(this._sidebar, 'collapsed')) { 176 | this.fire('closing'); 177 | L.DomUtil.addClass(this._sidebar, 'collapsed'); 178 | } 179 | 180 | return this; 181 | }, 182 | 183 | /** 184 | * @private 185 | */ 186 | _onClick: function() { 187 | if (L.DomUtil.hasClass(this, 'active')) 188 | this._sidebar.close(); 189 | else if (!L.DomUtil.hasClass(this, 'disabled')) 190 | this._sidebar.open(this.querySelector('a').hash.slice(1)); 191 | }, 192 | 193 | /** 194 | * @private 195 | */ 196 | _onCloseClick: function () { 197 | this.close(); 198 | } 199 | }); 200 | 201 | /** 202 | * Creates a new sidebar. 203 | * 204 | * @example 205 | * var sidebar = L.control.sidebar('sidebar').addTo(map); 206 | * 207 | * @param {string} id - The id of the sidebar element (without the # character) 208 | * @param {Object} [options] - Optional options object 209 | * @param {string} [options.position=left] - Position of the sidebar: 'left' or 'right' 210 | * @returns {Sidebar} A new sidebar instance 211 | */ 212 | L.control.sidebar = function (id, options) { 213 | return new L.Control.Sidebar(id, options); 214 | }; 215 | -------------------------------------------------------------------------------- /static/resources/text_species.txt: -------------------------------------------------------------------------------- 1 | Egg 2 | Bulbasaur 3 | Ivysaur 4 | Venusaur 5 | Charmander 6 | Charmeleon 7 | Charizard 8 | Squirtle 9 | Wartortle 10 | Blastoise 11 | Caterpie 12 | Metapod 13 | Butterfree 14 | Weedle 15 | Kakuna 16 | Beedrill 17 | Pidgey 18 | Pidgeotto 19 | Pidgeot 20 | Rattata 21 | Raticate 22 | Spearow 23 | Fearow 24 | Ekans 25 | Arbok 26 | Pikachu 27 | Raichu 28 | Sandshrew 29 | Sandslash 30 | Nidoran♀ 31 | Nidorina 32 | Nidoqueen 33 | Nidoran♂ 34 | Nidorino 35 | Nidoking 36 | Clefairy 37 | Clefable 38 | Vulpix 39 | Ninetales 40 | Jigglypuff 41 | Wigglytuff 42 | Zubat 43 | Golbat 44 | Oddish 45 | Gloom 46 | Vileplume 47 | Paras 48 | Parasect 49 | Venonat 50 | Venomoth 51 | Diglett 52 | Dugtrio 53 | Meowth 54 | Persian 55 | Psyduck 56 | Golduck 57 | Mankey 58 | Primeape 59 | Growlithe 60 | Arcanine 61 | Poliwag 62 | Poliwhirl 63 | Poliwrath 64 | Abra 65 | Kadabra 66 | Alakazam 67 | Machop 68 | Machoke 69 | Machamp 70 | Bellsprout 71 | Weepinbell 72 | Victreebel 73 | Tentacool 74 | Tentacruel 75 | Geodude 76 | Graveler 77 | Golem 78 | Ponyta 79 | Rapidash 80 | Slowpoke 81 | Slowbro 82 | Magnemite 83 | Magneton 84 | Farfetch’d 85 | Doduo 86 | Dodrio 87 | Seel 88 | Dewgong 89 | Grimer 90 | Muk 91 | Shellder 92 | Cloyster 93 | Gastly 94 | Haunter 95 | Gengar 96 | Onix 97 | Drowzee 98 | Hypno 99 | Krabby 100 | Kingler 101 | Voltorb 102 | Electrode 103 | Exeggcute 104 | Exeggutor 105 | Cubone 106 | Marowak 107 | Hitmonlee 108 | Hitmonchan 109 | Lickitung 110 | Koffing 111 | Weezing 112 | Rhyhorn 113 | Rhydon 114 | Chansey 115 | Tangela 116 | Kangaskhan 117 | Horsea 118 | Seadra 119 | Goldeen 120 | Seaking 121 | Staryu 122 | Starmie 123 | Mr. Mime 124 | Scyther 125 | Jynx 126 | Electabuzz 127 | Magmar 128 | Pinsir 129 | Tauros 130 | Magikarp 131 | Gyarados 132 | Lapras 133 | Ditto 134 | Eevee 135 | Vaporeon 136 | Jolteon 137 | Flareon 138 | Porygon 139 | Omanyte 140 | Omastar 141 | Kabuto 142 | Kabutops 143 | Aerodactyl 144 | Snorlax 145 | Articuno 146 | Zapdos 147 | Moltres 148 | Dratini 149 | Dragonair 150 | Dragonite 151 | Mewtwo 152 | Mew 153 | Chikorita 154 | Bayleef 155 | Meganium 156 | Cyndaquil 157 | Quilava 158 | Typhlosion 159 | Totodile 160 | Croconaw 161 | Feraligatr 162 | Sentret 163 | Furret 164 | Hoothoot 165 | Noctowl 166 | Ledyba 167 | Ledian 168 | Spinarak 169 | Ariados 170 | Crobat 171 | Chinchou 172 | Lanturn 173 | Pichu 174 | Cleffa 175 | Igglybuff 176 | Togepi 177 | Togetic 178 | Natu 179 | Xatu 180 | Mareep 181 | Flaaffy 182 | Ampharos 183 | Bellossom 184 | Marill 185 | Azumarill 186 | Sudowoodo 187 | Politoed 188 | Hoppip 189 | Skiploom 190 | Jumpluff 191 | Aipom 192 | Sunkern 193 | Sunflora 194 | Yanma 195 | Wooper 196 | Quagsire 197 | Espeon 198 | Umbreon 199 | Murkrow 200 | Slowking 201 | Misdreavus 202 | Unown 203 | Wobbuffet 204 | Girafarig 205 | Pineco 206 | Forretress 207 | Dunsparce 208 | Gligar 209 | Steelix 210 | Snubbull 211 | Granbull 212 | Qwilfish 213 | Scizor 214 | Shuckle 215 | Heracross 216 | Sneasel 217 | Teddiursa 218 | Ursaring 219 | Slugma 220 | Magcargo 221 | Swinub 222 | Piloswine 223 | Corsola 224 | Remoraid 225 | Octillery 226 | Delibird 227 | Mantine 228 | Skarmory 229 | Houndour 230 | Houndoom 231 | Kingdra 232 | Phanpy 233 | Donphan 234 | Porygon2 235 | Stantler 236 | Smeargle 237 | Tyrogue 238 | Hitmontop 239 | Smoochum 240 | Elekid 241 | Magby 242 | Miltank 243 | Blissey 244 | Raikou 245 | Entei 246 | Suicune 247 | Larvitar 248 | Pupitar 249 | Tyranitar 250 | Lugia 251 | Ho-Oh 252 | Celebi 253 | Treecko 254 | Grovyle 255 | Sceptile 256 | Torchic 257 | Combusken 258 | Blaziken 259 | Mudkip 260 | Marshtomp 261 | Swampert 262 | Poochyena 263 | Mightyena 264 | Zigzagoon 265 | Linoone 266 | Wurmple 267 | Silcoon 268 | Beautifly 269 | Cascoon 270 | Dustox 271 | Lotad 272 | Lombre 273 | Ludicolo 274 | Seedot 275 | Nuzleaf 276 | Shiftry 277 | Taillow 278 | Swellow 279 | Wingull 280 | Pelipper 281 | Ralts 282 | Kirlia 283 | Gardevoir 284 | Surskit 285 | Masquerain 286 | Shroomish 287 | Breloom 288 | Slakoth 289 | Vigoroth 290 | Slaking 291 | Nincada 292 | Ninjask 293 | Shedinja 294 | Whismur 295 | Loudred 296 | Exploud 297 | Makuhita 298 | Hariyama 299 | Azurill 300 | Nosepass 301 | Skitty 302 | Delcatty 303 | Sableye 304 | Mawile 305 | Aron 306 | Lairon 307 | Aggron 308 | Meditite 309 | Medicham 310 | Electrike 311 | Manectric 312 | Plusle 313 | Minun 314 | Volbeat 315 | Illumise 316 | Roselia 317 | Gulpin 318 | Swalot 319 | Carvanha 320 | Sharpedo 321 | Wailmer 322 | Wailord 323 | Numel 324 | Camerupt 325 | Torkoal 326 | Spoink 327 | Grumpig 328 | Spinda 329 | Trapinch 330 | Vibrava 331 | Flygon 332 | Cacnea 333 | Cacturne 334 | Swablu 335 | Altaria 336 | Zangoose 337 | Seviper 338 | Lunatone 339 | Solrock 340 | Barboach 341 | Whiscash 342 | Corphish 343 | Crawdaunt 344 | Baltoy 345 | Claydol 346 | Lileep 347 | Cradily 348 | Anorith 349 | Armaldo 350 | Feebas 351 | Milotic 352 | Castform 353 | Kecleon 354 | Shuppet 355 | Banette 356 | Duskull 357 | Dusclops 358 | Tropius 359 | Chimecho 360 | Absol 361 | Wynaut 362 | Snorunt 363 | Glalie 364 | Spheal 365 | Sealeo 366 | Walrein 367 | Clamperl 368 | Huntail 369 | Gorebyss 370 | Relicanth 371 | Luvdisc 372 | Bagon 373 | Shelgon 374 | Salamence 375 | Beldum 376 | Metang 377 | Metagross 378 | Regirock 379 | Regice 380 | Registeel 381 | Latias 382 | Latios 383 | Kyogre 384 | Groudon 385 | Rayquaza 386 | Jirachi 387 | Deoxys 388 | Turtwig 389 | Grotle 390 | Torterra 391 | Chimchar 392 | Monferno 393 | Infernape 394 | Piplup 395 | Prinplup 396 | Empoleon 397 | Starly 398 | Staravia 399 | Staraptor 400 | Bidoof 401 | Bibarel 402 | Kricketot 403 | Kricketune 404 | Shinx 405 | Luxio 406 | Luxray 407 | Budew 408 | Roserade 409 | Cranidos 410 | Rampardos 411 | Shieldon 412 | Bastiodon 413 | Burmy 414 | Wormadam 415 | Mothim 416 | Combee 417 | Vespiquen 418 | Pachirisu 419 | Buizel 420 | Floatzel 421 | Cherubi 422 | Cherrim 423 | Shellos 424 | Gastrodon 425 | Ambipom 426 | Drifloon 427 | Drifblim 428 | Buneary 429 | Lopunny 430 | Mismagius 431 | Honchkrow 432 | Glameow 433 | Purugly 434 | Chingling 435 | Stunky 436 | Skuntank 437 | Bronzor 438 | Bronzong 439 | Bonsly 440 | Mime Jr. 441 | Happiny 442 | Chatot 443 | Spiritomb 444 | Gible 445 | Gabite 446 | Garchomp 447 | Munchlax 448 | Riolu 449 | Lucario 450 | Hippopotas 451 | Hippowdon 452 | Skorupi 453 | Drapion 454 | Croagunk 455 | Toxicroak 456 | Carnivine 457 | Finneon 458 | Lumineon 459 | Mantyke 460 | Snover 461 | Abomasnow 462 | Weavile 463 | Magnezone 464 | Lickilicky 465 | Rhyperior 466 | Tangrowth 467 | Electivire 468 | Magmortar 469 | Togekiss 470 | Yanmega 471 | Leafeon 472 | Glaceon 473 | Gliscor 474 | Mamoswine 475 | Porygon-Z 476 | Gallade 477 | Probopass 478 | Dusknoir 479 | Froslass 480 | Rotom 481 | Uxie 482 | Mesprit 483 | Azelf 484 | Dialga 485 | Palkia 486 | Heatran 487 | Regigigas 488 | Giratina 489 | Cresselia 490 | Phione 491 | Manaphy 492 | Darkrai 493 | Shaymin 494 | Arceus 495 | Victini 496 | Snivy 497 | Servine 498 | Serperior 499 | Tepig 500 | Pignite 501 | Emboar 502 | Oshawott 503 | Dewott 504 | Samurott 505 | Patrat 506 | Watchog 507 | Lillipup 508 | Herdier 509 | Stoutland 510 | Purrloin 511 | Liepard 512 | Pansage 513 | Simisage 514 | Pansear 515 | Simisear 516 | Panpour 517 | Simipour 518 | Munna 519 | Musharna 520 | Pidove 521 | Tranquill 522 | Unfezant 523 | Blitzle 524 | Zebstrika 525 | Roggenrola 526 | Boldore 527 | Gigalith 528 | Woobat 529 | Swoobat 530 | Drilbur 531 | Excadrill 532 | Audino 533 | Timburr 534 | Gurdurr 535 | Conkeldurr 536 | Tympole 537 | Palpitoad 538 | Seismitoad 539 | Throh 540 | Sawk 541 | Sewaddle 542 | Swadloon 543 | Leavanny 544 | Venipede 545 | Whirlipede 546 | Scolipede 547 | Cottonee 548 | Whimsicott 549 | Petilil 550 | Lilligant 551 | Basculin 552 | Sandile 553 | Krokorok 554 | Krookodile 555 | Darumaka 556 | Darmanitan 557 | Maractus 558 | Dwebble 559 | Crustle 560 | Scraggy 561 | Scrafty 562 | Sigilyph 563 | Yamask 564 | Cofagrigus 565 | Tirtouga 566 | Carracosta 567 | Archen 568 | Archeops 569 | Trubbish 570 | Garbodor 571 | Zorua 572 | Zoroark 573 | Minccino 574 | Cinccino 575 | Gothita 576 | Gothorita 577 | Gothitelle 578 | Solosis 579 | Duosion 580 | Reuniclus 581 | Ducklett 582 | Swanna 583 | Vanillite 584 | Vanillish 585 | Vanilluxe 586 | Deerling 587 | Sawsbuck 588 | Emolga 589 | Karrablast 590 | Escavalier 591 | Foongus 592 | Amoonguss 593 | Frillish 594 | Jellicent 595 | Alomomola 596 | Joltik 597 | Galvantula 598 | Ferroseed 599 | Ferrothorn 600 | Klink 601 | Klang 602 | Klinklang 603 | Tynamo 604 | Eelektrik 605 | Eelektross 606 | Elgyem 607 | Beheeyem 608 | Litwick 609 | Lampent 610 | Chandelure 611 | Axew 612 | Fraxure 613 | Haxorus 614 | Cubchoo 615 | Beartic 616 | Cryogonal 617 | Shelmet 618 | Accelgor 619 | Stunfisk 620 | Mienfoo 621 | Mienshao 622 | Druddigon 623 | Golett 624 | Golurk 625 | Pawniard 626 | Bisharp 627 | Bouffalant 628 | Rufflet 629 | Braviary 630 | Vullaby 631 | Mandibuzz 632 | Heatmor 633 | Durant 634 | Deino 635 | Zweilous 636 | Hydreigon 637 | Larvesta 638 | Volcarona 639 | Cobalion 640 | Terrakion 641 | Virizion 642 | Tornadus 643 | Thundurus 644 | Reshiram 645 | Zekrom 646 | Landorus 647 | Kyurem 648 | Keldeo 649 | Meloetta 650 | Genesect 651 | Chespin 652 | Quilladin 653 | Chesnaught 654 | Fennekin 655 | Braixen 656 | Delphox 657 | Froakie 658 | Frogadier 659 | Greninja 660 | Bunnelby 661 | Diggersby 662 | Fletchling 663 | Fletchinder 664 | Talonflame 665 | Scatterbug 666 | Spewpa 667 | Vivillon 668 | Litleo 669 | Pyroar 670 | Flabébé 671 | Floette 672 | Florges 673 | Skiddo 674 | Gogoat 675 | Pancham 676 | Pangoro 677 | Furfrou 678 | Espurr 679 | Meowstic 680 | Honedge 681 | Doublade 682 | Aegislash 683 | Spritzee 684 | Aromatisse 685 | Swirlix 686 | Slurpuff 687 | Inkay 688 | Malamar 689 | Binacle 690 | Barbaracle 691 | Skrelp 692 | Dragalge 693 | Clauncher 694 | Clawitzer 695 | Helioptile 696 | Heliolisk 697 | Tyrunt 698 | Tyrantrum 699 | Amaura 700 | Aurorus 701 | Sylveon 702 | Hawlucha 703 | Dedenne 704 | Carbink 705 | Goomy 706 | Sliggoo 707 | Goodra 708 | Klefki 709 | Phantump 710 | Trevenant 711 | Pumpkaboo 712 | Gourgeist 713 | Bergmite 714 | Avalugg 715 | Noibat 716 | Noivern 717 | Xerneas 718 | Yveltal 719 | Zygarde 720 | Diancie 721 | Hoopa 722 | Volcanion 723 | Rowlet 724 | Dartrix 725 | Decidueye 726 | Litten 727 | Torracat 728 | Incineroar 729 | Popplio 730 | Brionne 731 | Primarina 732 | Pikipek 733 | Trumbeak 734 | Toucannon 735 | Yungoos 736 | Gumshoos 737 | Grubbin 738 | Charjabug 739 | Vikavolt 740 | Crabrawler 741 | Crabominable 742 | Oricorio 743 | Cutiefly 744 | Ribombee 745 | Rockruff 746 | Lycanroc 747 | Wishiwashi 748 | Mareanie 749 | Toxapex 750 | Mudbray 751 | Mudsdale 752 | Dewpider 753 | Araquanid 754 | Fomantis 755 | Lurantis 756 | Morelull 757 | Shiinotic 758 | Salandit 759 | Salazzle 760 | Stufful 761 | Bewear 762 | Bounsweet 763 | Steenee 764 | Tsareena 765 | Comfey 766 | Oranguru 767 | Passimian 768 | Wimpod 769 | Golisopod 770 | Sandygast 771 | Palossand 772 | Pyukumuku 773 | Type: Null 774 | Silvally 775 | Minior 776 | Komala 777 | Turtonator 778 | Togedemaru 779 | Mimikyu 780 | Bruxish 781 | Drampa 782 | Dhelmise 783 | Jangmo-o 784 | Hakamo-o 785 | Kommo-o 786 | Tapu Koko 787 | Tapu Lele 788 | Tapu Bulu 789 | Tapu Fini 790 | Cosmog 791 | Cosmoem 792 | Solgaleo 793 | Lunala 794 | Nihilego 795 | Buzzwole 796 | Pheromosa 797 | Xurkitree 798 | Celesteela 799 | Kartana 800 | Guzzlord 801 | Necrozma 802 | Magearna 803 | Marshadow 804 | Poipole 805 | Naganadel 806 | Stakataka 807 | Blacephalon 808 | Zeraora 809 | Meltan 810 | Melmetal 811 | Grookey 812 | Thwackey 813 | Rillaboom 814 | Scorbunny 815 | Raboot 816 | Cinderace 817 | Sobble 818 | Drizzile 819 | Inteleon 820 | Skwovet 821 | Greedent 822 | Rookidee 823 | Corvisquire 824 | Corviknight 825 | Blipbug 826 | Dottler 827 | Orbeetle 828 | Nickit 829 | Thievul 830 | Gossifleur 831 | Eldegoss 832 | Wooloo 833 | Dubwool 834 | Chewtle 835 | Drednaw 836 | Yamper 837 | Boltund 838 | Rolycoly 839 | Carkol 840 | Coalossal 841 | Applin 842 | Flapple 843 | Appletun 844 | Silicobra 845 | Sandaconda 846 | Cramorant 847 | Arrokuda 848 | Barraskewda 849 | Toxel 850 | Toxtricity 851 | Sizzlipede 852 | Centiskorch 853 | Clobbopus 854 | Grapploct 855 | Sinistea 856 | Polteageist 857 | Hatenna 858 | Hattrem 859 | Hatterene 860 | Impidimp 861 | Morgrem 862 | Grimmsnarl 863 | Obstagoon 864 | Perrserker 865 | Cursola 866 | Sirfetch’d 867 | Mr. Rime 868 | Runerigus 869 | Milcery 870 | Alcremie 871 | Falinks 872 | Pincurchin 873 | Snom 874 | Frosmoth 875 | Stonjourner 876 | Eiscue 877 | Indeedee 878 | Morpeko 879 | Cufant 880 | Copperajah 881 | Dracozolt 882 | Arctozolt 883 | Dracovish 884 | Arctovish 885 | Duraludon 886 | Dreepy 887 | Drakloak 888 | Dragapult 889 | Zacian 890 | Zamazenta 891 | Eternatus 892 | Kubfu 893 | Urshifu 894 | Zarude 895 | Regieleki 896 | Regidrago 897 | Glastrier 898 | Spectrier 899 | Calyrex 900 | Wyrdeer 901 | Kleavor 902 | Ursaluna 903 | Basculegion 904 | Sneasler 905 | Overqwil 906 | Enamorus -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """Flask application to display live memory information from 2 | PLA onto a map""" 3 | import json 4 | from math import factorial 5 | import struct 6 | import requests 7 | from flask import Flask, render_template, request 8 | import nxreader 9 | from pa8 import Pa8 10 | from xoroshiro import XOROSHIRO 11 | 12 | with open("./static/resources/text_natures.txt",encoding="utf-8") as text_natures: 13 | NATURES = text_natures.read().split("\n") 14 | with open("./static/resources/text_species.txt",encoding="utf-8") as text_species: 15 | SPECIES = text_species.read().split("\n") 16 | PLAYER_LOCATION_PTR = "[[[[[[main+42F18E8]+88]+90]+1F0]+18]+80]+90" 17 | SPAWNER_PTR = "[[main+42a6ee0]+330]" 18 | PARTY_PTR = "[[[main+42a7000]+d0]+58]" 19 | WILD_PTR = "[[[[main+42a6f00]+b0]+e0]+d0]" 20 | OUTBREAK_PTR = "[[[[main+42BA6B0]+2B0]+58]+18]" 21 | CUSTOM_MARKERS = { 22 | "obsidianfieldlands": { 23 | "camp": { 24 | "coords": [ 25 | 365.36, 26 | 52, 27 | 136.1 28 | ], 29 | "faIcon": "campground", 30 | } 31 | }, 32 | "crimsonmirelands": { 33 | "camp": { 34 | "coords": [ 35 | 242.45, 36 | 55.64, 37 | 435.84 38 | ], 39 | "faIcon": "campground", 40 | } 41 | }, 42 | "cobaltcoastlands": { 43 | "camp": { 44 | "coords": [ 45 | 71.06, 46 | 45.16, 47 | 625.38 48 | ], 49 | "faIcon": "campground", 50 | } 51 | }, 52 | "coronethighlands": { 53 | "camp": { 54 | "coords": [ 55 | 892.75, 56 | 36.45, 57 | 922.92 58 | ], 59 | "faIcon": "campground", 60 | } 61 | }, 62 | "alabastericelands": { 63 | "camp": { 64 | "coords": [ 65 | 533.77, 66 | 31.13, 67 | 912.42 68 | ], 69 | "faIcon": "campground", 70 | } 71 | } 72 | } 73 | 74 | with open("config.json","r",encoding="utf-8") as config: 75 | IP_ADDRESS = json.load(config)["IP"] 76 | 77 | app = Flask(__name__) 78 | reader = nxreader.NXReader(IP_ADDRESS) 79 | 80 | def generate_from_seed(seed,rolls,guaranteed_ivs): 81 | """Generate pokemon information from a fixed seed (FixInitSpec)""" 82 | rng = XOROSHIRO(seed) 83 | encryption_constant = rng.rand(0xFFFFFFFF) 84 | sidtid = rng.rand(0xFFFFFFFF) 85 | for _ in range(rolls): 86 | pid = rng.rand(0xFFFFFFFF) 87 | shiny = ((pid >> 16) ^ (sidtid >> 16) ^ (pid & 0xFFFF) ^ (sidtid & 0xFFFF)) < 0x10 88 | if shiny: 89 | break 90 | ivs = [-1,-1,-1,-1,-1,-1] 91 | for i in range(guaranteed_ivs): 92 | index = rng.rand(6) 93 | while ivs[index] != -1: 94 | index = rng.rand(6) 95 | ivs[index] = 31 96 | for i in range(6): 97 | if ivs[i] == -1: 98 | ivs[i] = rng.rand(32) 99 | ability = rng.rand(2) 100 | gender = rng.rand(252) + 1 101 | nature = rng.rand(25) 102 | return encryption_constant,pid,ivs,ability,gender,nature,shiny 103 | 104 | @app.route("/") 105 | def root(): 106 | """Display index.html at the root of the application""" 107 | return render_template('index.html') 108 | 109 | @app.route("/map/") 110 | def load_map(name): 111 | """Read markers and generate map based on location""" 112 | url = "https://raw.githubusercontent.com/Lincoln-LM/JS-Finder/main/Resources/" \ 113 | f"pla_spawners/jsons/{name}.json" 114 | markers = json.loads(requests.get(url).text) 115 | with open(f"./static/resources/{name}.json",encoding="utf-8") as slot_file: 116 | slots = json.load(slot_file) 117 | return render_template('map.html', 118 | markers=markers.values(), 119 | map_name=name, 120 | custom_markers=json.dumps(CUSTOM_MARKERS[name]), 121 | slots=slots) 122 | 123 | def slot_to_pokemon(values,slot): 124 | """Compare slot to list of slots to find pokemon""" 125 | for pokemon,slot_value in values.items(): 126 | if slot <= slot_value: 127 | return pokemon 128 | slot -= slot_value 129 | return None 130 | 131 | def find_slots(time,weather,sp_slots): 132 | """Get slots based on sp_slots, time, and weather""" 133 | for time_weather, values in sp_slots.items(): 134 | slot_time,slot_weather = time_weather.split("/") 135 | if (slot_time in ("Any Time", time)) and (slot_weather in ("All Weather", weather)): 136 | return values 137 | return None 138 | 139 | def find_slot_range(time,weather,species,sp_slots): 140 | """Find slot range of a species for a spawner""" 141 | values = find_slots(time,weather,sp_slots) 142 | pokemon = list(values.keys()) 143 | slot_values = list(values.values()) 144 | if not species in pokemon: 145 | return 0,0,0 146 | start = sum(slot_values[:pokemon.index(species)]) 147 | end = start + values[species] 148 | return start,end,sum(slot_values) 149 | 150 | def next_filtered(group_id, 151 | rolls, 152 | guaranteed_ivs, 153 | init_spawn, 154 | poke_filter, 155 | stopping_point=50000): 156 | """Find the next advance that matches poke_filter for a spawner""" 157 | # pylint: disable=too-many-locals,too-many-arguments 158 | generator_seed = reader.read_pointer_int(f"{SPAWNER_PTR}"\ 159 | f"+{0x70+group_id*0x440+0x20:X}",8) 160 | group_seed = (generator_seed - 0x82A2B175229D6A5B) & 0xFFFFFFFFFFFFFFFF 161 | main_rng = XOROSHIRO(group_seed) 162 | if not init_spawn: 163 | # advance once 164 | main_rng.next() # spawner 0 165 | main_rng.next() # spawner 1 166 | main_rng.reseed(main_rng.next()) 167 | adv = -1 168 | if poke_filter['slotTotal'] == 0: 169 | return -1,-1,-1,-1,[],-1,-1,-1,False 170 | while True: 171 | adv += 1 172 | if adv > stopping_point: 173 | return -2,-1,-1,-1,[],-1,-1,-1,False 174 | generator_seed = main_rng.next() 175 | main_rng.next() # spawner 1's seed, unused 176 | rng = XOROSHIRO(generator_seed) 177 | slot = poke_filter['slotTotal'] * rng.next() / 2**64 178 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 179 | generate_from_seed(rng.next(),rolls,guaranteed_ivs) 180 | break_flag = ((poke_filter['shinyFilterCheck'] and not shiny) 181 | or poke_filter['slotFilterCheck'] 182 | and not (poke_filter['minSlotFilter'] <= slot < poke_filter['maxSlotFilter']) 183 | or poke_filter['outbreakAlphaFilter'] and not 100 <= slot < 101) 184 | if not break_flag: 185 | break 186 | main_rng.reseed(main_rng.next()) 187 | return adv,slot,encryption_constant,pid,ivs,ability,gender,nature,shiny 188 | 189 | def generate_mass_outbreak(main_rng,rolls,spawns,poke_filter): 190 | """Generate the current set of a mass outbreak and return a string representing it along with 191 | a bool to show if a pokemon passing poke_filter is present""" 192 | # pylint: disable=too-many-locals 193 | # this many locals is appropriate to display all the information about 194 | # the mass outbreak that a user might want 195 | display = "" 196 | filtered_present = False 197 | for init_spawn in range(1,5): 198 | generator_seed = main_rng.next() 199 | main_rng.next() # spawner 1's seed, unused 200 | fixed_rng = XOROSHIRO(generator_seed) 201 | slot = (fixed_rng.next() / (2**64) * 101) 202 | alpha = slot >= 100 203 | fixed_seed = fixed_rng.next() 204 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 205 | generate_from_seed(fixed_seed,rolls,3 if alpha else 0) 206 | display += f"Init Spawn {init_spawn} Shiny: " \ 207 | f"{shiny}
    " \ 208 | f"Alpha: " \ 209 | f"{alpha}
    " \ 210 | f"EC: {encryption_constant:08X} PID: {pid:08X}
    " \ 211 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 212 | f"{'/'.join(str(iv) for iv in ivs)}
    " 213 | filtered = ((poke_filter['shinyFilterCheck'] and not shiny) 214 | or poke_filter['outbreakAlphaFilter'] and not 100 <= slot < 101) 215 | filtered_present |= not filtered 216 | group_seed = main_rng.next() 217 | main_rng.reseed(group_seed) 218 | respawn_rng = XOROSHIRO(group_seed) 219 | for respawn in range(1,spawns-3): 220 | generator_seed = respawn_rng.next() 221 | respawn_rng.next() # spawner 1's seed, unused 222 | respawn_rng.reseed(respawn_rng.next()) 223 | fixed_rng = XOROSHIRO(generator_seed) 224 | slot = (fixed_rng.next() / (2**64) * 101) 225 | alpha = slot >= 100 226 | fixed_seed = fixed_rng.next() 227 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 228 | generate_from_seed(fixed_seed,rolls,3 if alpha else 0) 229 | display += f"Respawn {respawn} Shiny: " \ 230 | f"{shiny}
    " \ 231 | f"Alpha: " \ 232 | f"{alpha}
    " \ 233 | f"EC: {encryption_constant:08X} PID: {pid:08X}
    " \ 234 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 235 | f"{'/'.join(str(iv) for iv in ivs)}
    " 236 | filtered = ((poke_filter['shinyFilterCheck'] and not shiny) 237 | or poke_filter['outbreakAlphaFilter'] and not 100 <= slot < 101) 238 | filtered_present |= not filtered 239 | return display,filtered_present 240 | 241 | def next_filtered_mass_outbreak(main_rng,rolls,spawns,poke_filter): 242 | """Find the next pokemon of a mass outbreak that passes poke_filter 243 | and return a string representing it""" 244 | filtered_present = False 245 | advance = 0 246 | while not filtered_present: 247 | advance += 1 248 | display, filtered_present = generate_mass_outbreak(main_rng,rolls,spawns,poke_filter) 249 | return f"Advance: {advance}
    {display}" 250 | 251 | def generate_mass_outbreak_passive_path(group_seed, 252 | rolls, 253 | steps, 254 | total_spawns, 255 | poke_filter, 256 | filtered_results, 257 | storage): 258 | """Generate all the pokemon of an outbreak based on a provided passive path""" 259 | # pylint: disable=too-many-locals, too-many-arguments 260 | # the generation is unique to each path, no use in splitting this function 261 | rng = XOROSHIRO(group_seed) 262 | passes_filters = False 263 | skip = 0 264 | for step_i in range(len(steps),0,-1): 265 | path_str = tuple(steps[:step_i]) 266 | if path_str in storage: 267 | rng.reseed(*storage[path_str]) # we've already calculated up to this point 268 | skip = step_i 269 | break 270 | for step_i,step in enumerate(steps[skip:]): 271 | step_i += skip 272 | path_str = tuple(steps[:step_i+1]) 273 | left = total_spawns - sum(steps[:step_i+1]) 274 | final_in_init = (step_i == (len(steps) - 1)) and left + step <= 4 275 | all_in_init = (step_i != (len(steps) - 1)) and left <= 4 276 | down_to_init = final_in_init or all_in_init 277 | if final_in_init: 278 | add = 0 279 | else: 280 | add = min(4,left) 281 | for pokemon in range(step + add): 282 | spawner_seed = rng.next() 283 | spawner_rng = XOROSHIRO(spawner_seed) 284 | slot = spawner_rng.next() / (2**64) * 101 285 | alpha = slot >= 100 286 | fixed_seed = spawner_rng.next() 287 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 288 | generate_from_seed(fixed_seed,rolls,3 if alpha else 0) 289 | filtered = ((poke_filter['shinyFilterCheck'] and not shiny) 290 | or poke_filter['outbreakAlphaFilter'] and not alpha) 291 | passes_filters |= not filtered 292 | if not filtered: 293 | effective_path = steps[:step_i] + [max(0,pokemon-3)] 294 | if fixed_seed in filtered_results["info"] \ 295 | and effective_path not in filtered_results["paths"][fixed_seed]: 296 | filtered_results["paths"][fixed_seed].append(effective_path) 297 | else: 298 | filtered_results["paths"][fixed_seed] = [effective_path] 299 | filtered_results["info"][fixed_seed] = \ 300 | f"Shiny: " \ 301 | f"{shiny}
    " \ 302 | f"Alpha: " \ 303 | f"{alpha}
    " \ 304 | f"EC: {encryption_constant:08X} PID: {pid:08X}
    " \ 305 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 306 | f"{'/'.join(str(iv) for iv in ivs)}" 307 | rng.next() # spawner 1 seed, unused 308 | if not down_to_init and pokemon >= 3: 309 | rng.reseed(rng.next()) 310 | storage[path_str] = rng.seed.copy() 311 | return passes_filters 312 | 313 | def generate_mass_outbreak_aggressive_path(group_seed,rolls,steps,poke_filter,uniques,storage): 314 | """Generate all the pokemon of an outbreak based on a provided aggressive path""" 315 | # pylint: disable=too-many-locals, too-many-arguments 316 | # the generation is unique to each path, no use in splitting this function 317 | main_rng = XOROSHIRO(group_seed) 318 | for init_spawn in range(1,5): 319 | generator_seed = main_rng.next() 320 | main_rng.next() # spawner 1's seed, unused 321 | fixed_rng = XOROSHIRO(generator_seed) 322 | slot = (fixed_rng.next() / (2**64) * 101) 323 | alpha = slot >= 100 324 | fixed_seed = fixed_rng.next() 325 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 326 | generate_from_seed(fixed_seed,rolls,3 if alpha else 0) 327 | filtered = ((poke_filter['shinyFilterCheck'] and not shiny) 328 | or poke_filter['outbreakAlphaFilter'] and not alpha) 329 | if not filtered and not fixed_seed in uniques: 330 | uniques.add(fixed_seed) 331 | storage.append( 332 | f"Init Spawn {init_spawn} Shiny: " 333 | f"{shiny}
    " 334 | f"Alpha: " \ 335 | f"{alpha}
    " \ 336 | f"EC: {encryption_constant:08X} PID: {pid:08X}
    " 337 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " 338 | f"{'/'.join(str(iv) for iv in ivs)}") 339 | group_seed = main_rng.next() 340 | respawn_rng = XOROSHIRO(group_seed) 341 | for step_i,step in enumerate(steps): 342 | for pokemon in range(1,step+1): 343 | generator_seed = respawn_rng.next() 344 | respawn_rng.next() # spawner 1's seed, unused 345 | fixed_rng = XOROSHIRO(generator_seed) 346 | slot = (fixed_rng.next() / (2**64) * 101) 347 | alpha = slot >= 100 348 | fixed_seed = fixed_rng.next() 349 | encryption_constant,pid,ivs,ability,gender,nature,shiny = \ 350 | generate_from_seed(fixed_seed,rolls,3 if alpha else 0) 351 | filtered = ((poke_filter['shinyFilterCheck'] and not shiny) 352 | or poke_filter['outbreakAlphaFilter'] and not alpha) 353 | if not filtered and not fixed_seed in uniques: 354 | uniques.add(fixed_seed) 355 | storage.append( 356 | f"Path: {'|'.join(str(s) for s in steps[:step_i]+[pokemon])} " \ 357 | f"Spawns: {sum(steps[:step_i]) + pokemon + 4} Shiny: " \ 358 | f"{shiny}
    " \ 359 | f"Alpha: " \ 360 | f"{alpha}
    " \ 361 | f"EC: {encryption_constant:08X} PID: {pid:08X}
    " \ 362 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 363 | f"{'/'.join(str(iv) for iv in ivs)}" 364 | ) 365 | respawn_rng = XOROSHIRO(respawn_rng.next()) 366 | 367 | def get_final(spawns): 368 | """Get the final path that will be generated to know when to stop aggressive recursion""" 369 | spawns -= 4 370 | path = [4] * (spawns // 4) 371 | if spawns % 4 != 0: 372 | path.append(spawns % 4) 373 | return path 374 | 375 | def generate_passive_search_paths(group_seed, 376 | rolls, 377 | spawns, 378 | move_limit, 379 | poke_filter, 380 | exhaustive_search): 381 | """Passively pathfind to all pokemon that pass poke_filter""" 382 | # pylint: disable=too-many-arguments,too-many-locals 383 | stack = [] 384 | filtered_results = {"info": {}, "paths": {}} 385 | storage = {} 386 | 387 | work = spawns * (spawns + 3) # impossibly high work 388 | total_paths = round(factorial(spawns - 4 + move_limit) \ 389 | / (factorial(spawns - 4) * factorial(move_limit))) 390 | progress_val = round(total_paths/100) # 1% 391 | progress_mask = XOROSHIRO.get_mask(progress_val+1) 392 | print(f"Progress update interval {progress_mask} (from {progress_val})") 393 | 394 | counter = 0 395 | for i in range(0, spawns + 1): 396 | stack.append((spawns - 4 - i, [i])) # remaining spawns, path 397 | 398 | while len(stack) > 0: 399 | spawns_left, path = stack.pop(0) # breadth first search 400 | if spawns_left <= 0 or len(path) > move_limit: 401 | continue 402 | 403 | if not exhaustive_search and len(path) * (spawns + 1) > work: 404 | break # results cannot get better 405 | 406 | counter = counter + 1 407 | if counter & progress_mask == 0: 408 | print(f"Scanned: {counter}/{total_paths} {counter/total_paths*100}%") 409 | 410 | passes_filters = generate_mass_outbreak_passive_path(group_seed, 411 | rolls, 412 | path, 413 | spawns, 414 | poke_filter, 415 | filtered_results, 416 | storage) 417 | 418 | c_work = len(path) * (spawns + 1) + sum(path) 419 | if passes_filters and c_work < work: 420 | if not exhaustive_search: 421 | return filtered_results 422 | 423 | if len(path) == move_limit: 424 | continue 425 | 426 | for i in range(0, spawns_left + 1): 427 | path_ = path.copy() 428 | path_.append(i) 429 | stack.append((spawns_left - i, path_)) 430 | return filtered_results 431 | 432 | def aggressive_outbreak_pathfind(group_seed, 433 | rolls, 434 | spawns, 435 | poke_filter, 436 | step=0, 437 | steps=None, 438 | uniques=None, 439 | storage=None): 440 | """Recursively pathfind to possible shinies for the current outbreak via multi battles""" 441 | # pylint: disable=too-many-arguments 442 | # can this algo be improved? 443 | if steps is None or uniques is None or storage is None: 444 | steps = [] 445 | uniques = set() 446 | storage = [] 447 | _steps = steps.copy() 448 | if step != 0: 449 | _steps.append(step) 450 | if sum(_steps) + step < spawns - 4: 451 | for _step in range(1, min(5, (spawns - 4) - sum(_steps))): 452 | if aggressive_outbreak_pathfind(group_seed, 453 | rolls, 454 | spawns, 455 | poke_filter, 456 | _step, 457 | _steps, 458 | uniques, 459 | storage) is not None: 460 | return storage 461 | else: 462 | _steps.append(spawns - sum(_steps) - 4) 463 | generate_mass_outbreak_aggressive_path(group_seed,rolls,_steps,poke_filter,uniques,storage) 464 | if _steps == get_final(spawns): 465 | return storage 466 | return None 467 | 468 | def next_filtered_aggressive_outbreak_pathfind(group_seed,rolls,spawns,poke_filter): 469 | """Check the next outbreak advances until an aggressive path to a pokemon that 470 | passes poke_filter exists""" 471 | main_rng = XOROSHIRO(group_seed) 472 | result = [] 473 | advance = -1 474 | while len(result) == 0: 475 | if advance != -1: 476 | for _ in range(4*2): 477 | main_rng.next() 478 | group_seed = main_rng.next() 479 | main_rng.reseed(group_seed) 480 | advance += 1 481 | result = aggressive_outbreak_pathfind(group_seed, rolls, spawns, poke_filter) 482 | info = '
    '.join(result) 483 | return f"Advance: {advance}
    {info}" 484 | 485 | @app.route('/read-battle', methods=['GET']) 486 | def read_battle(): 487 | """Read all battle pokemon and return the information as an html formatted string""" 488 | display = "" 489 | party_count = reader.read_pointer_int(f"{PARTY_PTR}+88",1) 490 | wild_count = reader.read_pointer_int(f"{WILD_PTR}+1a0",1) \ 491 | - party_count 492 | if wild_count > 30: 493 | wild_count = 0 494 | for i in range(wild_count): 495 | pkm = Pa8(reader.read_pointer(f"{WILD_PTR}+{0xb0+8*(i+party_count):X}"\ 496 | "]+70]+60]+98]+10]",Pa8.STOREDSIZE)) 497 | pokemon_name = f"{SPECIES[pkm.species]}" \ 498 | f"{('-' + str(pkm.form_index)) if pkm.form_index > 0 else ''} " \ 499 | f"{'' if pkm.shiny_type == 0 else '⋆' if pkm.shiny_type == 1 else '◇'}" 500 | pokemon_info = f"EC: {pkm.encryption_constant:08X}
    " \ 501 | f"PID: {pkm.pid:08X}
    " \ 502 | f"Nature: {NATURES[pkm.nature]}
    " \ 503 | f"Ability: {pkm.ability_string}
    " \ 504 | f"IVs: {'/'.join(str(iv) for iv in pkm.ivs)}" 505 | if pkm.is_valid: 506 | display += f"" \ 509 | f"
    {pokemon_info}

    " 510 | return display 511 | 512 | @app.route('/read-mass-outbreak', methods=['POST']) 513 | def read_mass_outbreak(): 514 | """Read current mass outbreak information and predict next pokemon that passes filter""" 515 | url = "https://raw.githubusercontent.com/Lincoln-LM/JS-Finder/main/Resources/" \ 516 | f"pla_spawners/jsons/{request.json['name']}.json" 517 | minimum = int(list(json.loads(requests.get(url).text).keys())[-1])-15 518 | group_id = minimum+30 519 | group_seed = 0 520 | while group_seed == 0 and group_id != minimum: 521 | group_id -= 1 522 | print(f"Finding group_id {minimum-group_id+30}/30") 523 | group_seed = reader.read_pointer_int(f"{SPAWNER_PTR}+{0x70+group_id*0x440+0x408:X}",8) 524 | if group_id == minimum: 525 | print("No mass outbreak found") 526 | return json.dumps(["No mass outbreak found","No mass outbreak found"]) 527 | print(f"Found group_id {group_id}") 528 | generator_seed = reader.read_pointer_int(f"{SPAWNER_PTR}+{0x70+group_id*0x440+0x20:X}",8) 529 | group_seed = (generator_seed - 0x82A2B175229D6A5B) & 0xFFFFFFFFFFFFFFFF 530 | if request.json['spawns'] == -1: 531 | for i in range(4): 532 | spawns = reader.read_pointer_int(f"{OUTBREAK_PTR}+{0x60+i*0x50:X}",1) 533 | if 10 <= spawns <= 15: 534 | request.json['spawns'] = spawns 535 | break 536 | print(f"Spawns: {request.json['spawns']}") 537 | if request.json['aggressivePath']: 538 | # should display multiple aggressive paths like whats done with passive 539 | display = ["", 540 | f"Group Seed: {group_seed:X}
    " 541 | + next_filtered_aggressive_outbreak_pathfind(group_seed, 542 | request.json['rolls'], 543 | request.json['spawns'], 544 | request.json['filter'])] 545 | elif request.json['passivePath']: 546 | full_info = generate_passive_search_paths(group_seed, 547 | request.json['rolls'], 548 | request.json['spawns'], 549 | request.json['passiveMoveLimit'], 550 | request.json['filter'], 551 | not request.json['passiveFindFirst']) 552 | display = ["",f"Group Seed: {group_seed:X}
    "] 553 | if len(full_info["info"]) == 0: 554 | display[1] += "No paths found" 555 | for seed,info in full_info["info"].items(): 556 | paths = full_info["paths"][seed] 557 | display[1] += "Paths:
    " 558 | for effective_path in paths: 559 | display[1] += \ 560 | f"{'|'.join(str(effective_step) for effective_step in effective_path)}
    " 561 | display[1] += f"
    {info}
    " 562 | else: 563 | main_rng = XOROSHIRO(group_seed) 564 | display = [f"Group Seed: {group_seed:X}
    " 565 | + generate_mass_outbreak(main_rng, 566 | request.json['rolls'], 567 | request.json['spawns'], 568 | request.json['filter'])[0], 569 | next_filtered_mass_outbreak(main_rng, 570 | request.json['rolls'], 571 | request.json['spawns'], 572 | request.json['filter'])] 573 | return json.dumps(display) 574 | 575 | @app.route('/check-possible', methods=['POST']) 576 | def check_possible(): 577 | """Check spawners that can spawn a given species""" 578 | print(request.json) 579 | url = "https://raw.githubusercontent.com/Lincoln-LM/JS-Finder/main/Resources/" \ 580 | f"pla_spawners/jsons/{request.json['name']}.json" 581 | markers = json.loads(requests.get(url).text) 582 | possible = {} 583 | for group_id, marker in markers.items(): 584 | with open(f"./static/resources/{request.json['name']}.json",encoding="utf-8") as slot_file: 585 | sp_slots = \ 586 | json.load(slot_file)[marker['name']] 587 | minimum, maximum, total \ 588 | = find_slot_range(request.json["filter"]["timeSelect"], 589 | request.json["filter"]["weatherSelect"], 590 | request.json["filter"]["speciesSelect"], 591 | sp_slots) 592 | if total: 593 | possible[group_id] = (maximum-minimum)/total*100 594 | return json.dumps(possible) 595 | 596 | @app.route('/read-seed', methods=['POST']) 597 | def read_seed(): 598 | """Read current information and next advance that passes filter for a spawner""" 599 | # pylint: disable=too-many-locals 600 | group_id = request.json['groupID'] 601 | thresh = request.json['thresh'] 602 | url = "https://raw.githubusercontent.com/Lincoln-LM/JS-Finder/main/Resources/" \ 603 | f"pla_spawners/jsons/{request.json['map']}.json" 604 | with open(f"./static/resources/{request.json['map']}.json",encoding="utf-8") as slot_file: 605 | sp_slots = \ 606 | json.load(slot_file)[json.loads(requests.get(url).text)[str(group_id)]['name']] 607 | generator_seed = reader.read_pointer_int(f"{SPAWNER_PTR}"\ 608 | f"+{0x70+group_id*0x440+0x20:X}",8) 609 | group_seed = (generator_seed - 0x82A2B175229D6A5B) & 0xFFFFFFFFFFFFFFFF 610 | rng = XOROSHIRO(group_seed) 611 | if not request.json['initSpawn']: 612 | # advance once 613 | rng.next() # spawner 0 614 | rng.next() # spawner 1 615 | rng.reseed(rng.next()) # reseed group rng 616 | rng.reseed(rng.next()) # use spawner 0 to reseed 617 | slot = rng.next() / (2**64) * request.json['filter']['slotTotal'] 618 | fixed_seed = rng.next() 619 | encryption_constant,pid,ivs,ability,gender,nature,shiny \ 620 | = generate_from_seed(fixed_seed,request.json['rolls'],request.json['ivs']) 621 | species = slot_to_pokemon(find_slots(request.json["filter"]["timeSelect"], 622 | request.json["filter"]["weatherSelect"], 623 | sp_slots),slot) 624 | display = f"Generator Seed: {generator_seed:X}
    " \ 625 | f"Species: {species}
    " \ 626 | f"Shiny: {shiny}
    " \ 627 | f"EC: {encryption_constant:X} PID: {pid:X}
    " \ 628 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 629 | f"{'/'.join(str(iv) for iv in ivs)}
    " 630 | if request.json['filter']['filterSpeciesCheck']: 631 | request.json['filter']['minSlotFilter'], \ 632 | request.json['filter']['maxSlotFilter'], \ 633 | request.json['filter']['slotTotal'] \ 634 | = find_slot_range(request.json["filter"]["timeSelect"], 635 | request.json["filter"]["weatherSelect"], 636 | request.json["filter"]["speciesSelect"], 637 | sp_slots) 638 | request.json['filter']['slotFilterCheck'] = True 639 | adv,slot,encryption_constant,pid,ivs,ability,gender,nature,shiny \ 640 | = next_filtered(group_id, 641 | request.json['rolls'], 642 | request.json['ivs'], 643 | request.json['initSpawn'], 644 | request.json['filter']) 645 | if adv == -1: 646 | return "Impossible slot filters for this spawner" 647 | if adv == -2: 648 | return "No results before limit (50000)" 649 | if adv <= thresh: 650 | display += f"Next Filtered: {adv}
    " 651 | else: 652 | display += f"Next Filtered: {adv}
    " 653 | 654 | species = slot_to_pokemon(find_slots(request.json["filter"]["timeSelect"], 655 | request.json["filter"]["weatherSelect"], 656 | sp_slots),slot) 657 | display += f"Species: {species}
    " \ 658 | f"Shiny: {shiny}
    " \ 659 | f"EC: {encryption_constant:X} PID: {pid:X}
    " \ 660 | f"Nature: {NATURES[nature]} Ability: {ability} Gender: {gender}
    " \ 661 | f"{'/'.join(str(iv) for iv in ivs)}
    " 662 | return display 663 | 664 | @app.route('/teleport', methods=['POST']) 665 | def teleport(): 666 | """Teleport the player to provided coordinates""" 667 | coordinates = request.json['coords'] 668 | print(f"Teleporting to {coordinates}") 669 | position_bytes = struct.pack('fff', *coordinates) 670 | reader.write_pointer(PLAYER_LOCATION_PTR,f"{int.from_bytes(position_bytes,'big'):024X}") 671 | return "" 672 | 673 | @app.route('/read-coords', methods=['GET']) 674 | def read_coords(): 675 | """Read the players current position""" 676 | pos = struct.unpack('fff', reader.read_pointer(PLAYER_LOCATION_PTR,12)) 677 | coords = { 678 | "x":pos[0], 679 | "y":pos[1], 680 | "z":pos[2] 681 | } 682 | return json.dumps(coords) 683 | 684 | @app.route('/update-positions', methods=['GET']) 685 | def update_positions(): 686 | """Scan all active spawns""" 687 | spawns = {} 688 | size = reader.read_pointer_int(f"{SPAWNER_PTR}+18",4) 689 | size = int(size//0x40 - 1) 690 | print(f"Checking up to index {size}") 691 | for index in range(0,size): 692 | if index % int(size//100) == 0: 693 | print(f"{index/size*100}% done scanning") 694 | position_bytes = reader.read_pointer(f"{SPAWNER_PTR}+{0x70+index*0x40:X}",12) 695 | seed = reader.read_pointer_int(f"{SPAWNER_PTR}+{0x90+index*0x40:X}",12) 696 | pos = struct.unpack('fff', position_bytes) 697 | if not (seed == 0 or pos[0] < 1 or pos[1] < 1 or pos[2] < 1): 698 | print(f"Active: spawner_id {index} {pos[0]},{pos[1]},{pos[2]} {seed:X}") 699 | spawns[str(index)] = {"x":pos[0], 700 | "y":pos[1], 701 | "z":pos[2], 702 | "seed":seed} 703 | return json.dumps(spawns) 704 | 705 | @app.route('/check-near', methods=['POST']) 706 | def check_near(): 707 | """Check all spawners' nearest advance that passes filters to update icons""" 708 | # pylint: disable=too-many-locals 709 | # store these locals before the loop to avoid accessing dictionary items repeatedly 710 | thresh = request.json['thresh'] 711 | name = request.json['name'] 712 | url = "https://raw.githubusercontent.com/Lincoln-LM/JS-Finder/main/Resources/" \ 713 | f"pla_spawners/jsons/{name}.json" 714 | markers = json.loads(requests.get(url).text) 715 | maximum = list(markers.keys())[-1] 716 | near = [] 717 | poke_filter = request.json['filter'] 718 | time = request.json["filter"]["timeSelect"] 719 | weather = request.json["filter"]["weatherSelect"] 720 | species = request.json["filter"]["speciesSelect"] 721 | with open(f"./static/resources/{name}.json",encoding="utf-8") as slot_file: 722 | slots = json.load(slot_file) 723 | for group_id, marker in markers.items(): 724 | if poke_filter['filterSpeciesCheck']: 725 | sp_slots = slots[markers[str(group_id)]['name']] 726 | poke_filter['minSlotFilter'], \ 727 | poke_filter['maxSlotFilter'], \ 728 | poke_filter['slotTotal'] \ 729 | = find_slot_range(time, 730 | weather, 731 | species, 732 | sp_slots) 733 | poke_filter['slotFilterCheck'] = True 734 | print(f"Checking group_id {group_id}/{maximum}") 735 | adv,_,_,_,_,_,_,_,_ = \ 736 | next_filtered(int(group_id), 737 | request.json['rolls'], 738 | marker["ivs"], 739 | request.json['initSpawn'], 740 | poke_filter, 741 | stopping_point=thresh) 742 | if 0 <= adv <= thresh: 743 | near.append(group_id) 744 | return json.dumps(near) 745 | 746 | if __name__ == '__main__': 747 | app.run(host="localhost", port=8080, debug=True) 748 | --------------------------------------------------------------------------------