diff --git a/.gitignore b/.gitignore index cb30b978fa..75bdb5ad83 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,6 @@ var/ .pydevproject .settings/ - # Installer logs pip-log.txt pip-delete-this-directory.txt @@ -98,19 +97,13 @@ ENV/ .idea/ # Personal load details -config.json src/ -info.json -inventory.json -pokedex.json -web/catchable.json -web/catchable-*.json -web/location-*.json -web/inventory-*.json -web/location.json -web/userdata.js +web/ data/last-location*.json data/catch-ignore.yml -release_config.json -web/userdata.js -location.json + +#Multiple config +configs/* +!configs/config.json.example +!configs/release_config.json.example +!configs/config.json.pokemons.example \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 7930970692..612529e7ad 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "origin"] +[submodule "web"] path = web url = https://github.com/OpenPoGo/OpenPoGoWeb.git \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3a9d0b9443..bffb4ce251 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,4 +10,4 @@ addons: install: - pip install -r requirements.txt - pip install pylint -script: "python travis-pythoncheck.py" +script: "python pylint-recursive.py" diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000000..3b215b11c5 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,33 @@ +## Contributors + * eggins [first pull request] + * crack00r + * ethervoid + * Bashin + * tstumm + * TheGoldenXY + * Reaver01 + * rarshonsky + * earthchie + * haykuro + * 05-032 + * sinistance + * CapCap + * mzupan + * gnekic(GeXx) + * Shoh + * luizperes + * brantje + * VirtualSatai + * dmateusp + * jtdroste + * msoedov + * Grace + * Calcyfer + * asaf400 + * guyz + * DavidK1m + * budi-khoirudin + * riberod07 + * th3w4y + * Leaklessgfy + * steffwiz diff --git a/README.md b/README.md index 77c4a53af8..b7a0480339 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,51 @@ -

- - Logo - -

+# PokemonGo-Bot +PokemonGo bot is a project created by the [PokemonGoF](https://github.com/PokemonGoF) team. +The project is currently setup in two different branches. `dev` and `master`. + +We use [Slack](https://slack.com) as a web chat. [Click here to join the chat!](https://pokemongo-bot.herokuapp.com) + +## Features +- [x] GPS Location configuration +- [x] Search Pokestops +- [x] Catch Pokemon +- [x] Determine which pokeball to use (uses Razz Berry if the catch percentage is low!) +- [x] Exchange Pokemon as per configuration +- [x] Evolve Pokemon as per configuration +- [x] Auto switch mode (Inventory Checks - switches between catch/farming items) +- [x] Limit the step to farm specific area for pokestops +- [x] Rudimentary IV Functionality filter +- [x] Ignore certain pokemon filter +- [ ] Standalone Desktop Application +- [ ] Hatch eggs +- [ ] Incubate eggs +- [ ] Use candy +- [ ] Fight Gym + +## Wiki +All information on [Getting Started](https://github.com/PokemonGoF/PokemonGo-Bot/wiki/Getting-Started) is available in the [Wiki](https://github.com/PokemonGoF/PokemonGo-Bot/wiki/)! +To ensure that all updates are documented - [@eggins](https://github.com/eggins) will keep the Wiki updated with the latest information on installing, updating and configuring the bot. + +## Credits +- [tejado](https://github.com/tejado) many thanks for the API +- [Mila432](https://github.com/Mila432/Pokemon_Go_API) for the login secrets +- [elliottcarlson](https://github.com/elliottcarlson) for the Google Auth PR +- [AeonLucid](https://github.com/AeonLucid/POGOProtos) for improved protos +- [AHAAAAAAA](https://github.com/AHAAAAAAA/PokemonGo-Map) for parts of the s2sphere stuff + + +## Donation + +Bitcoin Address: 1PJMCx9NNQRasQYaa4MMff9yyNFffhHgLu

- Slack +

-# PokemonGo-Bot -The Pokemon Go Bot, baking with community. -## Project Chat -We use [Slack](https://slack.com) as a web chat. [Click here to join the chat!](https://pokemongo-bot.herokuapp.com) -## Breaking Changes -You need modify config.json (config.json.example for example) then pokecli.py --config config.json -Please clean up your old clone if you have issue, and following the [install instruction](https://github.com/PokemonGoF/PokemonGo-Bot#installation). - -## About dev/master Branch -Dev branch has most up to date feature and even everyone handle the part well, still, will have broken changes. Your test contribute and PR for fix are warm welcome. -Master branch is the stable branch. -No PR on master branch to keep things easier. + +## OLD README BELOW. STILL UPDATING THIS. + ## Table of Contents -- [Project Chat](#project-chat) -- [Features](#features) -- [TODO List](#todo-list) - __Installation__ - [Requirements](#requirements) - [Mac](#installation-mac) @@ -37,33 +58,6 @@ No PR on master branch to keep things easier. - [Credits](#credits) - [Donation](#donation) -## Features - * Search Fort (Spin Pokestop) - * Catch Pokemon - * Release low cp pokemon - * Walking as you - * Limit the step to farm specific area for pokestops - * Use the ball you have to catch, don't if you don't have - * Rudimentary IV Functionality filter - * Auto switch mode(Full of item then catch, no ball useable then farm) - * Ignore certain pokemon filter - * Use superior ball types when necessary - * When out of normal pokeballs, use the next type of ball unless there are less than 10 of that type, in which case switch to farm mode - * Drop items when bag is full (In Testing, Document contribute needed) - * Pokemon catch filter (In Testing, Document contribute needed) - * Google Map API key setup (Readme update needed) - * Show all objects on map (In Testing) - * Evolve pokemons (Code in, Need input, In Testing) - -## TODO List - -- [ ] Standalone Desktop APP -- [ ] Pokemon transfer filter ?? This already done, right? -- [ ] Hatch eggs -- [ ] Incubate eggs -- [ ] Use candy -- [ ] Fight Gym - ## Installation ### Requirements (click each one for install guide) @@ -82,10 +76,10 @@ No PR on master branch to keep things easier. - Linux: `apt-get install python-protobuf` ### Note on branch -Please keep in mind that master is not always up to date whereas 'dev' is. In the installation note below change `master` to `dev` if you want to get the latest version. +Please keep in mind that master is not always up-to-date whereas 'dev' is. In the installation note below change `master` to `dev` if you want to get and use the latest version. ### Installation Linux -(change master to dev for the newer version) +(change master to dev for the latest version) ``` $ git clone -b master https://github.com/PokemonGoF/PokemonGo-Bot @@ -96,7 +90,7 @@ $ git submodule update ``` ### Installation Mac -(change master to dev for the newer version) +(change master to dev for the latest version) ``` $ git clone -b master https://github.com/PokemonGoF/PokemonGo-Bot @@ -109,7 +103,7 @@ $ git submodule update ``` ### Installation Windows -(change master to dev for the newer version) +(change master to dev for the latest version) On Windows, you will need to install PyYaml through the installer and not through requirements.txt. @@ -128,7 +122,7 @@ $ pip install PyYAML-3.11-cp27-cp27m-win32.whl // (replace PyYAML-3.11-cp27-cp27m-win32.whl with PyYAML-3.11-cp27-cp27m-win_amd64.whl ``` -After this, just do : +After this, just do: ``` $ git clone -b master https://github.com/PokemonGoF/PokemonGo-Bot @@ -164,20 +158,20 @@ This project uses Google Maps. There's one map coupled with the project, but as 6. After the code done, will update here how to replace. ### Python possible bug -If you encounter problems with the module `ssl` and it function `_create_unverified_context`. Just comment it. (Solution available in Python 2.7.11) -To do it follow instruction below : +If you encounter problems with the module `ssl` and it's function `_create_unverified_context`, just comment it. (Solution available in Python 2.7.11) +In order to comment out the function and the module, please follow the instructions below: - edit `pokecli.py` - put `#` before `if` (line 43) and `ssl` (line 44) - save it -Please keep in mind that this fix is necessary only if your python version don't have the `_create_unverified_context` argument in ssl module. +Please keep in mind that this fix is only necessary if your python version don't have the `_create_unverified_context` argument in the ssl module. ## Update To update your project do: `git pull` in the project folder -## Usage (up to date) - 1/ copy `config.json.example` to `config.json` and `release_config.json.example` to `release_config.json`. - 2/ Edit `config.json` and replace `auth_service`, `username`, `password`, `location` and `gmapkey` with your parameters (others keys are optional, check `Advance Configuration` below) +## Usage (up-to-date) + 1/ copy `config.json.example` to `config.json` and `release_config.json.example` to `release_config.json`. + 2/ Edit `config.json` and replace `auth_service`, `username`, `password`, `location` and `gmapkey` with your parameters (other keys are optional, check `Advance Configuration` below) ## Advance Configuration - `max_steps` : @@ -189,7 +183,27 @@ To update your project do: `git pull` in the project folder - `location_cache` : - `distance_unit` : - `item_filter` : -- `evolve_all` : Set to true to evolve pokemon if possible +- `evolve_all` : Set to true to evolve pokemons if possible + +## Catch Configuration +Default configuration will capture all Pokemon. +```"any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}``` +You can override the global configuration with Pokemon-specific options, such as: +```"Pidgey": {"catch_above_cp": 0, "catch_above_iv": 0.8", "logic": "and"}``` +to only capture Pidgey with a good roll. +Additionally, you can specify always_capture and never_capture flags. For example: +```"Pidgey": {"never_capture": true}``` +will stop catching Pidgey entirely. + +## Release Configuration +Default configuration will not release any Pokemon. +```"any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}``` +You can override the global configuration with Pokemon-specific options, such as: +```"Pidgey": {"release_below_cp": 0, "release_below_iv": 0.8", "logic": "or"}``` +to only release Pidgey with bad rolls. +Additionally, you can specify always_release and never_release flags. For example: +```"Pidgey": {"always_release": true}``` +will release all Pidgey caught. ### Evolve All Configuration By setting the `evolve_all` attribute in config.json, you can instruct the bot to automatically @@ -238,7 +252,7 @@ sudo apt-get install nginx #### 2. Check the webserver Check if the webserver is running by using your browser and entering the IP address of your local machine/server. -On a local machine this would be http://127.0.0.1. On AWS this is your public DNS if you havent configured an elastic IP. +On a local machine this would be http://127.0.0.1. On AWS this is your public DNS if you haven't configured an elastic IP. #### 3. Change Base Directory of the Webserver ``` @@ -254,7 +268,7 @@ Comment out following line: ```root /var/www/html;``` and change it to the web f ### What's IV ? Here's the [introduction](http://bulbapedia.bulbagarden.net/wiki/Individual_values) -### Does it run automatally? +### Does it run automatically? Not yet, still need a trainer to train the script param. But we are very close to. ### Set GEO Location It works, use -l "xx.yyyy,zz.ttttt" to set lat long for location. -- diordache @@ -264,7 +278,7 @@ Try to generate an [app password](!https://support.google.com/accounts/answer/18 ``` -p "" ``` -This error is mostly occurs for those who using 2 factor authentication but either way for the purpose of security would be nice to have a separate password for the bot app. +This error mostly occurs for those who are using 2 factor authentication, but either way, for the purpose of security it would be nice to have a separate password for the bot app. ### FLEE @@ -282,7 +296,7 @@ Create the following filter ``` ./data/catch-ignore.yml ``` -Its a yaml file with a list of names so make it look like +It's a yaml file with a list of names so make it look like ``` ignore: - Pidgey @@ -305,52 +319,3 @@ If using multiple usernames format like this: ```var users = ["username1","username2"];``` --------- -## Contributors (Don't forget add yours here when you create PR) - * eggins -- The first pull request :) - * crack00r - * ethervoid - * Bashin - * tstumm - * TheGoldenXY - * Reaver01 - * rarshonsky - * earthchie - * haykuro - * 05-032 - * sinistance - * CapCap - * mzupan - * gnekic(GeXx) - * Shoh - * luizperes - * brantje - * VirtualSatai - * dmateusp - * jtdroste - * msoedov - * Grace - * Calcyfer - * asaf400 - * guyz - * DavidK1m - * budi-khoirudin - * riberod07 - * th3w4y - * Leaklessgfy - -------- -## Credits -- [tejado](https://github.com/tejado) many thanks for the API -- [Mila432](https://github.com/Mila432/Pokemon_Go_API) for the login secrets -- [elliottcarlson](https://github.com/elliottcarlson) for the Google Auth PR -- [AeonLucid](https://github.com/AeonLucid/POGOProtos) for improved protos -- [AHAAAAAAA](https://github.com/AHAAAAAAA/PokemonGo-Map) for parts of the s2sphere stuff - - -## Donation - -Bitcoin Address: 1PJMCx9NNQRasQYaa4MMff9yyNFffhHgLu - -

- -

diff --git a/config.json.example b/config.json.example deleted file mode 100644 index 3245708e6d..0000000000 --- a/config.json.example +++ /dev/null @@ -1,17 +0,0 @@ -{ - "auth_service": "google", - "username": "YOURACCOUNT@gmail.com", - "password": "YOURPASSWORD", - "location": "SOME LOCATION", - "gmapkey": "AGMAPAPIKEY", - "max_steps": 5, - "mode": "all", - "walk": 4.16, - "debug": false, - "test": false, - "initial_transfer": 0, - "location_cache": true, - "distance_unit": "km", - "item_filter": "101,102,103,104", - "evolve_all": "NONE" -} diff --git a/configs/config.json.example b/configs/config.json.example new file mode 100644 index 0000000000..11665d4413 --- /dev/null +++ b/configs/config.json.example @@ -0,0 +1,27 @@ +{ + "auth_service": "google", + "username": "YOUR_USERNAME", + "password": "YOUR_PASSWORD", + "location": "SOME_LOCATION", + "gmapkey": "GOOGLE_MAPS_API_KEY", + "max_steps": 5, + "mode": "all", + "walk": 4.16, + "debug": false, + "test": false, + "initial_transfer": 0, + "location_cache": true, + "distance_unit": "km", + "item_filter": "", + "evolve_all": "NONE", + "use_lucky_egg": false, + "evolve_captured": false, + "catch": { + "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or"}, + // "Rattata": { "always_catch" : true } + }, + "release": { + "any": {"release_below_cp": 0, "release_below_iv": 0, "logic": "or"}, + // "Rattata": { "always_release" : true } + } +} \ No newline at end of file diff --git a/configs/config.json.pokemons.example b/configs/config.json.pokemons.example new file mode 100644 index 0000000000..c919d15540 --- /dev/null +++ b/configs/config.json.pokemons.example @@ -0,0 +1,267 @@ +{ + "auth_service": "google", + "username": "YOUR_USERNAME", + "password": "YOUR_PASSWORD", + "location": "SOME_LOCATION", + "gmapkey": "GOOGLE_MAPS_API_KEY", + "max_steps": 5, + "mode": "all", + "walk": 4.16, + "debug": false, + "test": false, + "initial_transfer": 0, + "location_cache": true, + "distance_unit": "km", + "item_filter": "", + "evolve_all": "NONE", + "use_lucky_egg": false, + "evolve_captured": false, + "catch": { + "any": {"catch_above_cp": 0, "catch_above_iv": 0, "logic": "or" }, + + "// Pokemons with example": { "always_catch": true }, + "// Gets filtered with release parameters": {}, + + "// Ledgendary pokemons (Goes under S-Tier)": {}, + "Lapras": { "always_catch": true }, + "Moltres": { "always_catch": true }, + "Zapdos": { "always_catch": true }, + "Articuno": { "always_catch": true }, + + "// S-Tier pokemons (if pokemon can be evolved into tier, list the representative)": {}, + "Mewtwo": { "always_catch": true }, + "Dragonite": { "always_catch": true }, + "Snorlax": { "always_catch": true }, + "// Mew evolves to Mewtwo": {}, + "Mew": { "always_catch": true }, + "Arcanine": { "always_catch": true }, + "Vaporeon": { "always_catch": true }, + "Gyarados": { "always_catch": true }, + "Exeggutor": { "always_catch": true }, + "Muk": { "always_catch": true }, + "Weezing": { "always_catch": true }, + "Flareon": { "always_catch": true }, + + "// Growlithe evolves to Arcanine": {}, + "Growlithe": { "catch_above_cp": 465, "catch_above_iv": 0.8, "cp_iv_logic": "and" }, + "// Dragonair evolves to Dragonite": {}, + "Dragonair": { "catch_above_cp": 0, "catch_above_iv": 0.8, "cp_iv_logic": "and" }, + "// Munchlax evolves to Snorlax": {}, + "Munchlax": { "catch_above_cp": 0, "catch_above_iv": 0.8, "cp_iv_logic": "and" }, + "// Grimer evolves to Muk": {}, + "Grimer": { "catch_above_cp": 448, "catch_above_iv": 0.8, "cp_iv_logic": "and" }, + + "// Magikarp evolves to Gyarados": {}, + "Magikarp": { "catch_above_cp": 91, "catch_above_iv": 0.9, "cp_iv_logic": "and" }, + "// Exeggcute evolves to Exeggutor": {}, + "Exeggcute": { "catch_above_cp": 384, "catch_above_iv": 0.8, "cp_iv_logic": "and" }, + "// Eevee evolves to many versions, like Vaporeon, Flareon": {}, + "Eevee": { "catch_above_cp": 376, "catch_above_iv": 0.8, "cp_iv_logic": "and"}, + + "// A-Tier pokemons": {}, + "Slowbro": { "always_catch": true }, + "Victreebel": { "always_catch": true }, + "Machamp": { "always_catch": true }, + "Poliwrath": { "always_catch": true }, + "Clefable": { "always_catch": true }, + "Nidoking": { "always_catch": true }, + "Venusaur": { "always_catch": true }, + "Charizard": { "always_catch": true }, + "Golduck": { "always_catch": true }, + "Nidoqueen": { "always_catch": true }, + "Vileplume": { "always_catch": true }, + "Blastoise": { "always_catch": true }, + "Omastar": { "always_catch": true }, + "Aerodactyl": { "always_catch": true }, + "Golem": { "always_catch": true }, + "Wigglytuff": { "always_catch": true }, + "Dewgong": { "always_catch": true }, + "Ninetales": { "always_catch": true }, + "Magmar": { "always_catch": true }, + "Kabutops": { "always_catch": true }, + "Electabuzz": { "always_catch": true }, + "Starmie": { "always_catch": true }, + "Jolteon": { "always_catch": true }, + "Rapidash": { "always_catch": true }, + "Pinsir": { "always_catch": true }, + "Scyther": { "always_catch": true }, + "Tentacruel": { "always_catch": true }, + "Gengar": { "always_catch": true }, + "Hypno": { "always_catch": true }, + "Pidgeot": { "always_catch": true }, + "Rhydon": { "always_catch": true }, + "Seaking": { "always_catch": true }, + "Kangaskhan": { "always_catch": true } + }, + "release": { + "any": {"release_under_cp": 0, "release_under_iv": 0, "logic": "or" }, + + "// Ledgendary pokemons (Goes under S-Tier)": {}, + "Lapras": { "release_under_cp": 1041, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Moltres": { "release_under_cp": 1132, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Zapdos": { "release_under_cp": 1087, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Articuno": { "release_under_cp": 1039, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + + "// S-Tier pokemons (if pokemon can be evolved into tier, list the representative)": {}, + "Mewtwo": { "release_under_cp": 1447, "release_under_iv": 0.8, "cp_iv_logic": "and"}, + "Dragonite": { "release_under_cp": 1221, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Snorlax": { "release_under_cp": 1087, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Mew evolves to Mewtwo": {}, + "Mew": { "release_under_cp": 1152, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Arcanine": { "release_under_cp": 1041, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Vaporeon": { "release_under_cp": 984, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Gyarados": { "release_under_cp": 938, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Exeggutor": { "release_under_cp": 1032, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Muk": { "release_under_cp": 909, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Weezing": { "release_under_cp": 784, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Flareon": { "release_under_cp": 924, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + + "// Growlithe evolves to Arcanine": {}, + "Growlithe": { "release_under_cp": 465, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Dragonair evolves to Dragonite": {}, + "Dragonair": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Munchlax evolves to Snorlax": {}, + "Munchlax": { "release_under_cp": 1221, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Grimer evolves to Muk": {}, + "Grimer": { "release_under_cp": 448, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Magikarp evolves to Gyarados": {}, + "Magikarp": { "release_under_cp": 91, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Exeggcute evolves to Exeggutor": {}, + "Exeggcute": { "release_under_cp": 384, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "// Eevee evolves to many versions, like Vaporeon, Flareon": {}, + "Eevee": { "release_under_cp": 376, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + + "// A-Tier pokemons": {}, + "Slowbro": { "release_under_cp": 907, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Victreebel": { "release_under_cp": 883, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Machamp": { "release_under_cp": 907, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Poliwrath": { "release_under_cp": 876, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Clefable": { "release_under_cp": 837, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Nidoking": { "release_under_cp": 864, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Venusaur": { "release_under_cp": 902, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Charizard": { "release_under_cp": 909, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Golduck": { "release_under_cp": 832, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Nidoqueen": { "release_under_cp": 868, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Vileplume": { "release_under_cp": 871, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Blastoise": { "release_under_cp": 888, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Omastar": { "release_under_cp": 780, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Aerodactyl": { "release_under_cp": 756, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Golem": { "release_under_cp": 804, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Wigglytuff": { "release_under_cp": 760, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Dewgong": { "release_under_cp": 748, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Ninetales": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Magmar": { "release_under_cp": 792, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kabutops": { "release_under_cp": 744, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Electabuzz": { "release_under_cp": 739, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Starmie": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Jolteon": { "release_under_cp": 746, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Rapidash": { "release_under_cp": 768, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Pinsir": { "release_under_cp": 741, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Scyther": { "release_under_cp": 724, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Tentacruel": { "release_under_cp": 775, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Gengar": { "release_under_cp": 724, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Hypno": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Pidgeot": { "release_under_cp": 729, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Rhydon": { "release_under_cp": 782, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Seaking": { "release_under_cp": 712, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kangaskhan": { "release_under_cp": 712, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + + "// Koffing evolves to Weezing (A-Tier)": {}, + "Koffing": { "release_under_cp": 403, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + + "// Below is B-tier and lower pokemons": {}, + "Magikarp": { "release_under_cp": 91, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Caterpie": { "release_under_cp": 156, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Weedle": { "release_under_cp": 156, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Diglett": { "release_under_cp": 158, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Metapod": { "release_under_cp": 168, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kakuna": { "release_under_cp": 170, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Rattata": { "release_under_cp": 204, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Abra": { "release_under_cp": 208, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Zubat": { "release_under_cp": 225, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Chansey": { "release_under_cp": 235, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Pidgey": { "release_under_cp": 237, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Spearow": { "release_under_cp": 240, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Meowth": { "release_under_cp": 264, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Krabby": { "release_under_cp": 276, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Sandshrew": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Poliwag": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Horsea": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Gastly": { "release_under_cp": 280, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Ekans": { "release_under_cp": 288, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Shellder": { "release_under_cp": 288, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Vulpix": { "release_under_cp": 290, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Voltorb": { "release_under_cp": 292, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Geodude": { "release_under_cp": 297, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Doduo": { "release_under_cp": 297, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Onix": { "release_under_cp": 300, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Mankey": { "release_under_cp": 307, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Pikachu": { "release_under_cp": 309, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Magnemite": { "release_under_cp": 312, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Tentacool": { "release_under_cp": 316, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Paras": { "release_under_cp": 319, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Jigglypuff": { "release_under_cp": 321, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Ditto": { "release_under_cp": 321, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Staryu": { "release_under_cp": 326, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Charmander": { "release_under_cp": 333, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Goldeen": { "release_under_cp": 336, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Squirtle": { "release_under_cp": 352, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Cubone": { "release_under_cp": 352, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Venonat": { "release_under_cp": 360, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Bulbasaur": { "release_under_cp": 374, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Drowzee": { "release_under_cp": 374, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Machop": { "release_under_cp": 381, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Psyduck": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Seel": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kabuto": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Bellsprout": { "release_under_cp": 391, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Omanyte": { "release_under_cp": 391, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kadabra": { "release_under_cp": 396, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Oddish": { "release_under_cp": 400, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Dugtrio": { "release_under_cp": 408, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Rhyhorn": { "release_under_cp": 412, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Clefairy": { "release_under_cp": 420, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Slowpoke": { "release_under_cp": 424, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Pidgeotto": { "release_under_cp": 427, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Farfetch'd": { "release_under_cp": 441, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Poliwhirl": { "release_under_cp": 468, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Nidorino": { "release_under_cp": 480, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Haunter": { "release_under_cp": 482, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Nidorina": { "release_under_cp": 489, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Graveler": { "release_under_cp": 501, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Beedrill": { "release_under_cp": 504, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Raticate": { "release_under_cp": 504, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Butterfree": { "release_under_cp": 508, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Hitmonlee": { "release_under_cp": 520, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Ponyta": { "release_under_cp": 530, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Hitmonchan": { "release_under_cp": 530, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Charmeleon": { "release_under_cp": 544, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Wartortle": { "release_under_cp": 552, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Persian": { "release_under_cp": 568, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Lickitung": { "release_under_cp": 568, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Ivysaur": { "release_under_cp": 571, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Electrode": { "release_under_cp": 576, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Marowak": { "release_under_cp": 578, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Gloom": { "release_under_cp": 590, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Porygon": { "release_under_cp": 590, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Seadra": { "release_under_cp": 597, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Jynx": { "release_under_cp": 600, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Weepinbell": { "release_under_cp": 602, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Tangela": { "release_under_cp": 607, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Fearow": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Parasect": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Machoke": { "release_under_cp": 614, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Arbok": { "release_under_cp": 616, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Sandslash": { "release_under_cp": 631, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Alakazam": { "release_under_cp": 633, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Kingler": { "release_under_cp": 636, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Dodrio": { "release_under_cp": 640, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Tauros": { "release_under_cp": 643, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Primeape": { "release_under_cp": 650, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Magneton": { "release_under_cp": 657, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Venomoth": { "release_under_cp": 660, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Golbat": { "release_under_cp": 672, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Raichu": { "release_under_cp": 708, "release_under_iv": 0.8, "cp_iv_logic": "and" }, + "Cloyster": { "release_under_cp": 717, "release_under_iv": 0.8, "cp_iv_logic": "and"} + } +} \ No newline at end of file diff --git a/pokecli.py b/pokecli.py index 07cf746c06..9a22a9f819 100755 --- a/pokecli.py +++ b/pokecli.py @@ -25,29 +25,25 @@ Author: tjado """ -import os -import re -import json import argparse -import time +import codecs +import json +import logging +import os import ssl import sys -import codecs from getpass import getpass -import logging -import requests -from pokemongo_bot import logger + from pokemongo_bot import PokemonGoBot -from pokemongo_bot.cell_workers.utils import print_green, print_yellow, print_red +from pokemongo_bot import logger if sys.version_info >= (2, 7, 9): ssl._create_default_https_context = ssl._create_unverified_context - def init_config(): parser = argparse.ArgumentParser() - config_file = "config.json" - release_config_json = "release_config.json" + config_file = "configs/config.json" + web_dir = "web" # If config file exists, load variables from json load = {} @@ -59,8 +55,12 @@ def init_config(): with open(config_arg) as data: load.update(json.load(data)) elif os.path.isfile(config_file): + logger.log('No config argument specified, checking for /configs/config.json', 'yellow') with open(config_file) as data: load.update(json.load(data)) + else: + logger.log('Error: No /configs/config.json or specified config', 'red') + # Read passed in Arguments required = lambda x: not x in load @@ -129,8 +129,8 @@ def init_config(): "-if", "--item_filter", help= - "Pass a list of unwanted items to recycle when collected at a Pokestop (e.g, \"101,102,103,104\" to recycle potions when collected)", - type=str, + "Pass a list of unwanted items to recycle when collected at a Pokestop (e.g, SYNTAX FOR CONFIG.JSON : [\"101\",\"102\",\"103\",\"104\"] to recycle potions when collected, SYNTAX FOR CONSOLE ARGUMENT : \"101\",\"102\",\"103\",\"104\")", + type=list, default=[]) parser.add_argument("-ev", @@ -144,6 +144,11 @@ def init_config(): help="(Ad-hoc mode) Bot will attempt to evolve all the pokemons captured!", type=bool, default=False) + parser.add_argument("-le", + "--use_lucky_egg", + help="Uses lucky egg when using evolve_all", + type=bool, + default=False) config = parser.parse_args() if not config.username and 'username' not in load: @@ -155,6 +160,8 @@ def init_config(): for key in config.__dict__: if key in load: config.__dict__[key] = load[key] + config.catch = load['catch'] + config.release = load['release'] if config.auth_service not in ['ptc', 'google']: logging.error("Invalid Auth service specified! ('ptc' or 'google')") @@ -164,56 +171,47 @@ def init_config(): parser.error("Needs either --use-location-cache or --location.") return None - if config.item_filter: - config.item_filter = [str(item_id) for item_id in config.item_filter.split(',')] + # When config.item_filter looks like "101,102,103" needs to be converted to ["101","102","103"] + if isinstance(config.item_filter, basestring): + config.item_filter= config.item_filter.split(",") - config.release_config = {} - if os.path.isfile(release_config_json): - with open(release_config_json) as data: - config.release_config.update(json.load(data)) - - web_index = 'web/index.html' - if config.gmapkey and os.path.isfile(web_index): - find_url = 'https:\/\/maps.googleapis.com\/maps\/api\/js\?key=\S*' - replace_url = "https://maps.googleapis.com/maps/api/js?key=%s&callback=initMap\"" - #Someone make this pretty! (Efficient) - with open(web_index, "r+") as sources: # r+ is read + write - lines = sources.readlines() - for line in lines: - sources.write(re.sub(r"%s" % find_url, replace_url % config.gmapkey, line)) + # create web dir if not exists + try: + os.makedirs(web_dir) + except OSError: + if not os.path.isdir(web_dir): + raise if config.evolve_all: config.evolve_all = [str(pokemon_name) for pokemon_name in config.evolve_all.split(',')] return config - def main(): + + logger.log('PokemonGO Bot v1.0', 'green') # log settings # log format #logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(module)10s] [%(levelname)5s] %(message)s') - sys.stdout = codecs.getwriter('utf8')(sys.stdout) sys.stderr = codecs.getwriter('utf8')(sys.stderr) config = init_config() if not config: return - - logger.log('[x] PokemonGO Bot v1.0', 'green') - logger.log('[x] Configuration initialized', 'yellow') + logger.log('Configuration initialized', 'yellow') try: bot = PokemonGoBot(config) bot.start() - logger.log('[x] Starting PokemonGo Bot....', 'green') + logger.log('Starting PokemonGo Bot....', 'green') while True: bot.take_step() except KeyboardInterrupt: - logger.log('[x] Exiting PokemonGo Bot', 'red') + logger.log('Exiting PokemonGo Bot', 'red') # TODO Add number of pokemon catched, pokestops visited, highest CP # pokemon catched, etc. diff --git a/pokemongo_bot/__init__.py b/pokemongo_bot/__init__.py index d6df1a38d7..8a864e37b3 100644 --- a/pokemongo_bot/__init__.py +++ b/pokemongo_bot/__init__.py @@ -1,24 +1,23 @@ # -*- coding: utf-8 -*- -import os -import logging -import googlemaps +import datetime import json +import logging import random -import threading -import datetime -import sys -import yaml -import logger import re +import sys +import time + +from geopy.geocoders import GoogleV3 from pgoapi import PGoApi +from pgoapi.utilities import f2i + +import logger from cell_workers import PokemonCatchWorker, SeenFortWorker, MoveToFortWorker, InitialTransferWorker, EvolveAllWorker -from cell_workers.utils import distance +from cell_workers.utils import distance, get_cellid, encode from human_behaviour import sleep -from stepper import Stepper -from geopy.geocoders import GoogleV3 -from math import radians, sqrt, sin, cos, atan2 from item_list import Item +from spiral_navigator import SpiralNavigator class PokemonGoBot(object): @@ -30,26 +29,127 @@ def __init__(self, config): def start(self): self._setup_logging() self._setup_api() - self.stepper = Stepper(self) + self.navigator = SpiralNavigator(self) random.seed() def take_step(self): - self.stepper.take_step() + location = self.navigator.take_step() + cells = self.find_close_cells(*location) + + for cell in cells: + self.work_on_cell(cell, location) + + def update_web_location(self, cells=[], lat=None, lng=None, alt=None): + # we can call the function with no arguments and still get the position and map_cells + if lat == None: + lat = self.position[0] + if lng == None: + lng = self.position[1] + if alt == None: + alt = self.position[2] + + if cells == []: + cellid = get_cellid(lat, lng) + timestamp = [0, ] * len(cellid) + self.api.get_map_objects( + latitude=f2i(lat), + longitude=f2i(lng), + since_timestamp_ms=timestamp, + cell_id=cellid + ) + response_dict = self.api.call() + map_objects = response_dict.get('responses', {}).get('GET_MAP_OBJECTS', {}) + status = map_objects.get('status', None) + cells = map_objects['map_cells'] + + user_web_location = 'web/location-%s.json' % (self.config.username) + # should check if file exists first but os is not imported here + # alt is unused atm but makes using *location easier + with open(user_web_location,'w') as outfile: + json.dump( + {'lat': lat, + 'lng': lng, + 'alt': alt, + 'cells': cells + }, outfile) + + user_data_lastlocation = 'data/last-location-%s.json' % (self.config.username) + with open(user_data_lastlocation, 'w') as outfile: + outfile.truncate() + json.dump({'lat': lat, 'lng': lng}, outfile) + + def find_close_cells(self, lat, lng): + cellid = get_cellid(lat, lng) + timestamp = [0, ] * len(cellid) + + self.api.get_map_objects( + latitude=f2i(lat), + longitude=f2i(lng), + since_timestamp_ms=timestamp, + cell_id=cellid + ) + response_dict = self.api.call() + map_objects = response_dict.get('responses', {}).get('GET_MAP_OBJECTS', {}) + status = map_objects.get('status', None) + + map_cells = [] + if status and status == 1: + map_cells = map_objects['map_cells'] + position = (lat, lng, 0) + map_cells.sort( + key=lambda x: distance( + lat, + lng, + x['forts'][0]['latitude'], + x['forts'][0]['longitude']) if x.get('forts', []) else 1e6 + ) + self.update_web_location(map_cells,lat,lng) + return map_cells + + def work_on_cell(self, cell, position): + # Check if session token has expired + self.check_session(position) - def work_on_cell(self, cell, position, include_fort_on_path): if self.config.evolve_all: - # Run evolve all once. Flip the bit. - print('[#] Attempting to evolve all pokemons ...') - worker = EvolveAllWorker(self) - worker.work() + # Will skip evolving if user wants to use an egg and there is none + skip_evolves = False + + # Pop lucky egg before evolving to maximize xp gain + use_lucky_egg = self.config.use_lucky_egg + lucky_egg_count = self.item_inventory_count(Item.ITEM_LUCKY_EGG.value) + + if use_lucky_egg and lucky_egg_count > 0: + logger.log('Using lucky egg ... you have {}' + .format(lucky_egg_count)) + response_dict_lucky_egg = self.use_lucky_egg() + if response_dict_lucky_egg and 'responses' in response_dict_lucky_egg and \ + 'USE_ITEM_XP_BOOST' in response_dict_lucky_egg['responses'] and \ + 'result' in response_dict_lucky_egg['responses']['USE_ITEM_XP_BOOST']: + result = response_dict_lucky_egg['responses']['USE_ITEM_XP_BOOST']['result'] + if result is 1: # Request success + logger.log('Successfully used lucky egg... ({} left!)' + .format(lucky_egg_count-1), 'green') + else: + logger.log('Failed to use lucky egg!', 'red') + skip_evolves = True + elif use_lucky_egg: #lucky_egg_count is 0 + # Skipping evolve so they aren't wasted + logger.log('No lucky eggs... skipping evolve!', 'yellow') + skip_evolves = True + + if not skip_evolves: + # Run evolve all once. + logger.log('Attempting to evolve all pokemons ...', 'cyan') + worker = EvolveAllWorker(self) + worker.work() + + # Flip the bit. self.config.evolve_all = [] - self._filter_ignored_pokemons(cell) - if (self.config.mode == "all" or self.config.mode == "poke") and 'catchable_pokemons' in cell and len(cell[ 'catchable_pokemons']) > 0: - logger.log('[#] Something rustles nearby!') + logger.log('Something rustles nearby!') # Sort all by distance from current pos- eventually this should # build graph & A* it cell['catchable_pokemons'].sort( @@ -57,15 +157,14 @@ def work_on_cell(self, cell, position, include_fort_on_path): lambda x: distance(self.position[0], self.position[1], x['latitude'], x['longitude'])) user_web_catchable = 'web/catchable-%s.json' % (self.config.username) - if os.path.isfile(user_web_catchable): # only write to file if it exists - for pokemon in cell['catchable_pokemons']: - with open(user_web_catchable, 'w') as outfile: - json.dump(pokemon, outfile) + for pokemon in cell['catchable_pokemons']: + with open(user_web_catchable, 'w') as outfile: + json.dump(pokemon, outfile) - if self.catch_pokemon(pokemon) == PokemonCatchWorker.NO_POKEBALLS: - break - with open(user_web_catchable, 'w') as outfile: - json.dump({}, outfile) + if self.catch_pokemon(pokemon) == PokemonCatchWorker.NO_POKEBALLS: + break + with open(user_web_catchable, 'w') as outfile: + json.dump({}, outfile) if (self.config.mode == "all" or self.config.mode == "poke" ) and 'wild_pokemons' in cell and len(cell['wild_pokemons']) > 0: @@ -78,18 +177,19 @@ def work_on_cell(self, cell, position, include_fort_on_path): if self.catch_pokemon(pokemon) == PokemonCatchWorker.NO_POKEBALLS: break if (self.config.mode == "all" or - self.config.mode == "farm") and include_fort_on_path: + self.config.mode == "farm"): if 'forts' in cell: # Only include those with a lat/long forts = [fort for fort in cell['forts'] if 'latitude' in fort and 'type' in fort] - gyms = [gym for gym in cell['forts'] if 'gym_points' in gym] + gyms = [gym for gym in cell['forts'] if 'gym_points' in gym] # Sort all by distance from current pos- eventually this should # build graph & A* it forts.sort(key=lambda x: distance(self.position[ 0], self.position[1], x['latitude'], x['longitude'])) + for fort in forts: worker = MoveToFortWorker(fort, self) worker.work() @@ -117,27 +217,43 @@ def _setup_logging(self): logging.getLogger("pgoapi").setLevel(logging.ERROR) logging.getLogger("rpc_api").setLevel(logging.ERROR) + def check_session(self, position): + # Check session expiry + if self.api._auth_provider and self.api._auth_provider._ticket_expire: + remaining_time = self.api._auth_provider._ticket_expire/1000 - time.time() + + if remaining_time < 60: + logger.log("Session stale, re-logging in", 'yellow') + self.position = position + self.login() + + + def login(self): + logger.log('Attempting login to Pokemon Go.', 'white') + self.api._auth_token = None + self.api._auth_provider = None + self.api._api_endpoint = None + lat, lng = self.position[0:2] + self.api.set_position(lat, lng, 0) + + while not self.api.login(self.config.auth_service, + str(self.config.username), + str(self.config.password)): + + logger.log('[X] Login Error, server busy', 'red') + logger.log('[X] Waiting 10 seconds to try again', 'red') + time.sleep(10) + + logger.log('Login to Pokemon Go successful.', 'green') + def _setup_api(self): # instantiate pgoapi self.api = PGoApi() - # check if the release_config file exists - try: - with open('release_config.json') as file: - pass - except: - # the file does not exist, warn the user and exit. - logger.log('[#] IMPORTANT: Rename and configure release_config.json.example for your Pokemon release logic first!', 'red') - exit(0) - # provide player position on the earth self._set_starting_position() - if not self.api.login(self.config.auth_service, - str(self.config.username), - str(self.config.password)): - logger.log('Login Error, server busy', 'red') - exit(0) + self.login() # chain subrequests (methods) into one RPC call @@ -155,6 +271,7 @@ def _setup_api(self): # @@@ TODO: Convert this to d/m/Y H:M:S creation_date = datetime.datetime.fromtimestamp( player['creation_timestamp_ms'] / 1e3) + creation_date = creation_date.strftime("%Y/%m/%d %H:%M:%S") pokecoins = '0' stardust = '0' @@ -164,28 +281,28 @@ def _setup_api(self): pokecoins = player['currencies'][0]['amount'] if 'amount' in player['currencies'][1]: stardust = player['currencies'][1]['amount'] - - logger.log('[#] Username: {username}'.format(**player)) - logger.log('[#] Acccount Creation: {}'.format(creation_date)) - logger.log('[#] Bag Storage: {}/{}'.format( - self.get_inventory_count('item'), player['max_item_storage'])) - logger.log('[#] Pokemon Storage: {}/{}'.format( - self.get_inventory_count('pokemon'), player[ - 'max_pokemon_storage'])) - logger.log('[#] Stardust: {}'.format(stardust)) - logger.log('[#] Pokecoins: {}'.format(pokecoins)) - logger.log('[#] PokeBalls: ' + str(balls_stock[1])) - logger.log('[#] GreatBalls: ' + str(balls_stock[2])) - logger.log('[#] UltraBalls: ' + str(balls_stock[3])) - + logger.log('') + logger.log('--- {username} ---'.format(**player), 'cyan') self.get_player_info() + logger.log('Pokemon Bag: {}/{}'.format(self.get_inventory_count('pokemon'), player['max_pokemon_storage']), 'cyan') + logger.log('Items: {}/{}'.format(self.get_inventory_count('item'), player['max_item_storage']), 'cyan') + logger.log('Stardust: {}'.format(stardust) + ' | Pokecoins: {}'.format(pokecoins), 'cyan') + # Pokeball Output + logger.log('PokeBalls: ' + str(balls_stock[1]) + + ' | GreatBalls: ' + str(balls_stock[2]) + + ' | UltraBalls: ' + str(balls_stock[3]), 'cyan') + logger.log('Razz Berries: ' + str(self.item_inventory_count(701)), 'cyan') + + logger.log('') if self.config.initial_transfer: worker = InitialTransferWorker(self) worker.work() - logger.log('[#]') + logger.log('') self.update_inventory() + # send empty map_cells and then our position + self.update_web_location([],*self.position) def catch_pokemon(self, pokemon): worker = PokemonCatchWorker(pokemon, self) @@ -205,6 +322,11 @@ def drop_item(self, item_id, count): #{'responses': {'RECYCLE_INVENTORY_ITEM': {'result': 1, 'new_count': 46}}, 'status_code': 1, 'auth_ticket': {'expire_timestamp_ms': 1469306228058L, 'start': '/HycFyfrT4t2yB2Ij+yoi+on778aymMgxY6RQgvrGAfQlNzRuIjpcnDd5dAxmfoTqDQrbz1m2dGqAIhJ+eFapg==', 'end': 'f5NOZ95a843tgzprJo4W7Q=='}, 'request_id': 8145806132888207460L} return inventory_req + def use_lucky_egg(self): + self.api.use_item_xp_boost(item_id=301) + inventory_req = self.api.call() + return inventory_req + def update_inventory(self): self.api.get_inventory() response = self.api.call() @@ -228,7 +350,7 @@ def update_inventory(self): continue self.inventory.append(item['inventory_item_data'][ 'item']) - + def pokeball_inventory(self): self.api.get_player().get_inventory() @@ -237,9 +359,8 @@ def pokeball_inventory(self): 'inventory_delta']['inventory_items'] user_web_inventory = 'web/inventory-%s.json' % (self.config.username) - if os.path.isfile(user_web_inventory): - with open(user_web_inventory, 'w') as outfile: - json.dump(inventory_dict, outfile) + with open(user_web_inventory, 'w') as outfile: + json.dump(inventory_dict, outfile) # get player balls stock # ---------------------- @@ -284,6 +405,8 @@ def item_inventory_count(self, id): def _set_starting_position(self): + has_position = False + if self.config.test: # TODO: Add unit tests return @@ -295,26 +418,29 @@ def _set_starting_position(self): self.position = location self.api.set_position(*self.position) logger.log('') - logger.log(u'[x] Address found: {}'.format(self.config.location.decode( + logger.log(u'Location Found: {}'.format(self.config.location.decode( 'utf-8'))) - logger.log('[x] Position in-game set as: {}'.format(self.position)) + logger.log('GeoPosition: {}'.format(self.position)) logger.log('') + has_position = True return except: logger.log('[x] The location given using -l could not be parsed. Checking for a cached location.') pass - if self.config.location_cache and not self.config.location: + if self.config.location_cache and not has_position: try: # # save location flag used to pull the last known location from # the location.json + logger.log('[x] Parsing cached location...') with open('data/last-location-%s.json' % (self.config.username)) as f: location_json = json.load(f) self.position = (location_json['lat'], location_json['lng'], 0.0) + print(self.position) self.api.set_position(*self.position) logger.log('') @@ -325,13 +451,11 @@ def _set_starting_position(self): self.position)) logger.log('') + has_position = True return except: - if not self.config.location: - sys.exit( - "No cached Location. Please specify initial location.") - else: - pass + sys.exit( + "No cached Location. Please specify initial location.") def _get_pos_by_name(self, location_name): # Check if the given location is already a coordinate. @@ -351,51 +475,13 @@ def _get_pos_by_name(self, location_name): return (loc.latitude, loc.longitude, loc.altitude) - def _filter_ignored_pokemons(self, cell): - process_ignore = False - try: - with open("./data/catch-ignore.yml", 'r') as y: - ignores = yaml.load(y)['ignore'] - if len(ignores) > 0: - process_ignore = True - except Exception, e: - pass - - if process_ignore: - # - # remove any wild pokemon - try: - for p in cell['wild_pokemons'][:]: - pokemon_id = p['pokemon_data']['pokemon_id'] - pokemon_name = filter( - lambda x: int(x.get('Number')) == pokemon_id, - self.pokemon_list)[0]['Name'] - - if pokemon_name in ignores: - cell['wild_pokemons'].remove(p) - except KeyError: - pass - - # - # remove catchable pokemon - try: - for p in cell['catchable_pokemons'][:]: - pokemon_id = p['pokemon_id'] - pokemon_name = filter( - lambda x: int(x.get('Number')) == pokemon_id, - self.pokemon_list)[0]['Name'] - - if pokemon_name in ignores: - cell['catchable_pokemons'].remove(p) - except KeyError: - pass - def heartbeat(self): self.api.get_player() self.api.get_hatched_eggs() self.api.get_inventory() self.api.check_awarded_badges() self.api.call() + self.update_web_location() # updates every tick def get_inventory_count(self, what): self.api.get_inventory() @@ -454,24 +540,14 @@ def get_player_info(self): int(playerdata.get('experience', 0))) if 'level' in playerdata: - logger.log( - '[#] -- Level: {level}'.format( - **playerdata)) - - if 'experience' in playerdata: - logger.log( - '[#] -- Experience: {experience}'.format( - **playerdata)) - logger.log( - '[#] -- Experience until next level: {}'.format( - nextlvlxp)) + if 'experience' in playerdata: + logger.log('Level: {level}'.format(**playerdata) + + ' (Next Level: {} XP)'.format(nextlvlxp) + + ' (Total: {experience} XP)'.format(**playerdata), 'cyan') + if 'pokemons_captured' in playerdata: - logger.log( - '[#] -- Pokemon Captured: {pokemons_captured}'.format( - **playerdata)) - - if 'poke_stop_visits' in playerdata: - logger.log( - '[#] -- Pokestops Visited: {poke_stop_visits}'.format( - **playerdata)) + if 'poke_stop_visits' in playerdata: + logger.log( + 'Pokemon Captured: {pokemons_captured}'.format(**playerdata) + + ' | Pokestops Visited: {poke_stop_visits}'.format(**playerdata), 'cyan') diff --git a/pokemongo_bot/cell_workers/evolve_all_worker.py b/pokemongo_bot/cell_workers/evolve_all_worker.py index 9c46dc7555..c3e40a2629 100644 --- a/pokemongo_bot/cell_workers/evolve_all_worker.py +++ b/pokemongo_bot/cell_workers/evolve_all_worker.py @@ -1,8 +1,9 @@ -from utils import distance, format_dist -from pokemongo_bot.human_behaviour import sleep -from pokemongo_bot import logger from sets import Set +from pokemongo_bot import logger +from pokemongo_bot.human_behaviour import sleep + + class EvolveAllWorker(object): def __init__(self, bot): self.api = bot.api diff --git a/pokemongo_bot/cell_workers/initial_transfer_worker.py b/pokemongo_bot/cell_workers/initial_transfer_worker.py index f09b91e07c..1419887a47 100644 --- a/pokemongo_bot/cell_workers/initial_transfer_worker.py +++ b/pokemongo_bot/cell_workers/initial_transfer_worker.py @@ -1,5 +1,4 @@ import json -import os from pokemongo_bot.human_behaviour import sleep from pokemongo_bot import logger @@ -11,13 +10,8 @@ def __init__(self, bot): self.api = bot.api def work(self): - logger.log('[x] Initial Transfer.') - - logger.log( - '[x] Preparing to transfer all duplicate Pokemon, keeping the highest CP of each type.') - - logger.log('[x] Will NOT transfer anything above CP {}'.format( - self.config.initial_transfer)) + logger.log('Cleaning up Pokemon Bag of anything below {} CP'.format( + self.config.initial_transfer), 'cyan') pokemon_groups = self._initial_transfer_get_groups() @@ -34,14 +28,14 @@ def work(self): if self.config.initial_transfer and group_cp[x] > self.config.initial_transfer: continue - print('[x] Transferring {} with CP {}'.format( + logger.log('Exchanging {} with {} CP'.format( self.pokemon_list[id - 1]['Name'], group_cp[x])) self.api.release_pokemon( pokemon_id=pokemon_groups[id][group_cp[x]]) response_dict = self.api.call() sleep(2) - logger.log('[x] Transferring Done.') + logger.log('Pokemon Bag has been cleaned up!', 'green') def _initial_transfer_get_groups(self): pokemon_groups = {} @@ -51,9 +45,8 @@ def _initial_transfer_get_groups(self): 'inventory_delta']['inventory_items'] user_web_inventory = 'web/inventory-%s.json' % (self.config.username) - if os.path.isfile(user_web_inventory): - with open(user_web_inventory, 'w') as outfile: - json.dump(inventory_dict, outfile) + with open(user_web_inventory, 'w') as outfile: + json.dump(inventory_dict, outfile) for pokemon in inventory_dict: try: diff --git a/pokemongo_bot/cell_workers/move_to_fort_worker.py b/pokemongo_bot/cell_workers/move_to_fort_worker.py index 3af7befcd3..2889d74d41 100644 --- a/pokemongo_bot/cell_workers/move_to_fort_worker.py +++ b/pokemongo_bot/cell_workers/move_to_fort_worker.py @@ -1,13 +1,15 @@ from utils import distance, format_dist from pokemongo_bot.human_behaviour import sleep from pokemongo_bot import logger +from pokemongo_bot.step_walker import StepWalker class MoveToFortWorker(object): def __init__(self, fort, bot): + self.bot = bot self.fort = fort self.api = bot.api self.config = bot.config - self.stepper = bot.stepper + self.navigator = bot.navigator self.position = bot.position def work(self): @@ -18,22 +20,34 @@ def work(self): dist = distance(self.position[0], self.position[1], lat, lng) - # print('[#] Found fort {} at distance {}m'.format(fortID, dist)) - logger.log('[#] Found fort {} at distance {}'.format( + # print('Found fort {} at distance {}m'.format(fortID, dist)) + logger.log('Found fort {} at distance {}'.format( fortID, format_dist(dist, unit))) if dist > 10: - logger.log('[#] Need to move closer to Pokestop') + logger.log('Need to move closer to Pokestop') position = (lat, lng, 0.0) if self.config.walk > 0: - self.stepper._walk_to(self.config.walk, *position) + step_walker = StepWalker( + self.bot, + self.config.walk, + self.api._position_lat, + self.api._position_lng, + position[0], + position[1] + ) + + while True: + if step_walker.step(): + break + else: self.api.set_position(*position) self.api.player_update(latitude=lat, longitude=lng) response_dict = self.api.call() - logger.log('[#] Arrived at Pokestop') + logger.log('Arrived at Pokestop') sleep(2) return response_dict diff --git a/pokemongo_bot/cell_workers/pokemon_catch_worker.py b/pokemongo_bot/cell_workers/pokemon_catch_worker.py index 05ace03865..ec5fc753d2 100644 --- a/pokemongo_bot/cell_workers/pokemon_catch_worker.py +++ b/pokemongo_bot/cell_workers/pokemon_catch_worker.py @@ -2,9 +2,10 @@ import time from sets import Set -from utils import distance -from pokemongo_bot.human_behaviour import sleep + from pokemongo_bot import logger +from pokemongo_bot.human_behaviour import sleep + class PokemonCatchWorker(object): BAG_FULL = 'bag_full' @@ -33,8 +34,11 @@ def work(self): if 'ENCOUNTER' in response_dict['responses']: if 'status' in response_dict['responses']['ENCOUNTER']: if response_dict['responses']['ENCOUNTER']['status'] is 7: - logger.log('[x] Pokemon Bag is full!', 'red') - return PokemonCatchWorker.BAG_FULL + if self.config.initial_transfer: + logger.log('Pokemon Bag is full!', 'red') + return PokemonCatchWorker.BAG_FULL + else: + raise RuntimeError('Pokemon Bag is full!') if response_dict['responses']['ENCOUNTER']['status'] is 1: cp = 0 @@ -59,10 +63,10 @@ def work(self): 'pokemon_id']) - 1 pokemon_name = self.pokemon_list[ int(pokemon_num)]['Name'] - logger.log('[#] A Wild {} appeared! [CP {}] [Potential {}]'.format( + logger.log('A Wild {} appeared! [CP {}] [Potential {}]'.format( pokemon_name, cp, pokemon_potential), 'yellow') - logger.log('[#] IV [Stamina/Attack/Defense] = [{}/{}/{}]'.format( + logger.log('IV [Stamina/Attack/Defense] = [{}/{}/{}]'.format( pokemon['pokemon_data']['individual_stamina'], pokemon['pokemon_data']['individual_attack'], pokemon['pokemon_data']['individual_defense'] @@ -71,6 +75,10 @@ def work(self): # Simulate app sleep(3) + if not self.should_capture_pokemon(pokemon_name, cp, pokemon_potential, response_dict): + #logger.log('[x] Rule prevents capture.') + return False + balls_stock = self.bot.pokeball_inventory() while(True): @@ -81,8 +89,32 @@ def work(self): pokeball = 2 # then use great balls elif balls_stock[3] > 0: # or if great balls are out of stock too, and player has ultra balls... pokeball = 3 # then use ultra balls + + ## Use berry to increase success chance. + berry_id = 701 # @ TODO: use better berries if possible + berries_count = self.bot.item_inventory_count(berry_id) + if(catch_rate[pokeball-1] < 0.5 and berries_count > 0): # and berry is in stock + success_percentage = '{0:.2f}'.format(catch_rate[pokeball-1]*100) + logger.log('Catch Rate with normal Pokeball is low ({}%). Throwing {}... ({} left!)'.format(success_percentage,self.item_list[str(berry_id)],berries_count-1)) + + if balls_stock[pokeball] is 0: + break + + self.api.use_item_capture( + item_id=berry_id, + encounter_id = encounter_id, + spawn_point_guid = spawnpoint_id + ) + response_dict = self.api.call() + if response_dict and response_dict['status_code'] is 1 and 'item_capture_mult' in response_dict['responses']['USE_ITEM_CAPTURE']: + + for i in range(len(catch_rate)): + catch_rate[i] = catch_rate[i] * response_dict['responses']['USE_ITEM_CAPTURE']['item_capture_mult'] + + success_percentage = '{0:.2f}'.format(catch_rate[pokeball-1]*100) + logger.log('Catch Rate with normal Pokeball has increased to {}%'.format(success_percentage)) else: - pokeball = 0 # player doesn't have any of pokeballs, great balls or ultra balls + logger.log('Fail to use berry. Status Code: {}'.format(response_dict['status_code']),'red') while(pokeball < 3): if catch_rate[pokeball-1] < 0.35 and balls_stock[pokeball+1] > 0: @@ -92,17 +124,17 @@ def work(self): break # @TODO, use the best ball in stock to catch VIP (Very Important Pokemon: Configurable) - - if pokeball is 0: + + if balls_stock[pokeball] is 0: logger.log( - '[x] Out of pokeballs, switching to farming mode...', 'red') + 'Out of pokeballs, switching to farming mode...', 'red') # Begin searching for pokestops. self.config.mode = 'farm' return PokemonCatchWorker.NO_POKEBALLS balls_stock[pokeball] = balls_stock[pokeball] - 1 success_percentage = '{0:.2f}'.format(catch_rate[pokeball-1]*100) - logger.log('[x] Using {} (chance: {}%)... ({} left!)'.format( + logger.log('Using {} (chance: {}%)... ({} left!)'.format( self.item_list[str(pokeball)], success_percentage, balls_stock[pokeball] @@ -126,23 +158,24 @@ def work(self): 'CATCH_POKEMON']['status'] if status is 2: logger.log( - '[-] Attempted to capture {}- failed.. trying again!'.format(pokemon_name), 'red') + '[-] Attempted to capture {} - failed.. trying again!'.format(pokemon_name), 'red') sleep(2) continue if status is 3: logger.log( - '[x] Oh no! {} vanished! :('.format(pokemon_name), 'red') + 'Oh no! {} vanished! :('.format(pokemon_name), 'red') if status is 1: - logger.log( - '[x] Captured {}! [CP {}] [IV {}]'.format( - pokemon_name, - cp, - pokemon_potential - ), 'green' - ) - + id_list2 = self.count_pokemon_inventory() - + + logger.log('Captured {}! [CP {}] [{}/{}/{}]'.format( + pokemon_name, + cp, + pokemon['pokemon_data']['individual_stamina'], + pokemon['pokemon_data']['individual_attack'], + pokemon['pokemon_data']['individual_defense'] + ), 'blue') + if self.config.evolve_captured: pokemon_to_transfer = list(Set(id_list2) - Set(id_list1)) self.api.evolve_pokemon(pokemon_id=pokemon_to_transfer[0]) @@ -150,10 +183,10 @@ def work(self): status = response_dict['responses']['EVOLVE_POKEMON']['result'] if status == 1: logger.log( - '[#] {} has been evolved!'.format(pokemon_name), 'green') + '{} has been evolved!'.format(pokemon_name), 'green') else: logger.log( - '[x] Failed to evolve {}!'.format(pokemon_name)) + 'Failed to evolve {}!'.format(pokemon_name)) if self.should_release_pokemon(pokemon_name, cp, pokemon_potential, response_dict): # Transfering Pokemon @@ -165,10 +198,8 @@ def work(self): self.transfer_pokemon( pokemon_to_transfer[0]) logger.log( - '[#] {} has been exchanged for candy!'.format(pokemon_name), 'green') - else: - logger.log( - '[x] Captured {}! [CP {}]'.format(pokemon_name, cp), 'green') + '{} has been exchanged for candy!'.format(pokemon_name), 'green') + break time.sleep(5) @@ -231,76 +262,96 @@ def counting_pokemon(self, response_dict, id_list): return id_list + def should_capture_pokemon(self, pokemon_name, cp, iv, response_dict): + catch_config = self._get_catch_config_for(pokemon_name) + cp_iv_logic = catch_config.get('logic') + if not cp_iv_logic: + cp_iv_logic = self._get_catch_config_for('any').get('logic', 'and') + + catch_results = { + 'cp': False, + 'iv': False, + } + + if catch_config.get('never_catch', False): + return False + + if catch_config.get('always_catch', False): + return True + + catch_cp = catch_config.get('catch_above_cp', 0) + if cp > catch_cp: + catch_results['cp'] = True + + catch_iv = catch_config.get('catch_above_iv', 0) + if iv > catch_iv: + catch_results['iv'] = True + + logic_to_function = { + 'or': lambda x, y: x or y, + 'and': lambda x, y: x and y + } + + #logger.log( + # "Catch config for {}: CP {} {} IV {}".format( + # pokemon_name, + # catch_cp, + # cp_iv_logic, + # catch_iv + # ), 'yellow' + #) + + return logic_to_function[cp_iv_logic](*catch_results.values()) + + def _get_catch_config_for(self, pokemon): + catch_config = self.config.catch.get(pokemon) + if not catch_config: + catch_config = self.config.catch['any'] + return catch_config + def should_release_pokemon(self, pokemon_name, cp, iv, response_dict): - if self._check_always_capture_exception_for(pokemon_name): + release_config = self._get_release_config_for(pokemon_name) + cp_iv_logic = release_config.get('logic') + if not cp_iv_logic: + cp_iv_logic = self._get_release_config_for('any').get('logic', 'and') + + release_results = { + 'cp': False, + 'iv': False, + } + + if release_config.get('never_release', False): return False - else: - release_config = self._get_release_config_for(pokemon_name) - cp_iv_logic = release_config.get('cp_iv_logic') - if not cp_iv_logic: - cp_iv_logic = self._get_release_config_for('any').get('cp_iv_logic', 'and') - - release_results = { - 'cp': False, - 'iv': False, - } - - if 'release_under_cp' in release_config: - min_cp = release_config['release_under_cp'] - if cp < min_cp: - release_results['cp'] = True - - if 'release_under_iv' in release_config: - min_iv = release_config['release_under_iv'] - if iv < min_iv: - release_results['iv'] = True - - if release_config.get('always_release'): - return True - - logic_to_function = { - 'or': lambda x, y: x or y, - 'and': lambda x, y: x and y - } - - #logger.log( - # "[x] Release config for {}: CP {} {} IV {}".format( - # pokemon_name, - # min_cp, - # cp_iv_logic, - # min_iv - # ), 'yellow' - #) - - return logic_to_function[cp_iv_logic](*release_results.values()) + + if release_config.get('always_release', False): + return True + + release_cp = release_config.get('release_below_cp', 0) + if cp < release_cp: + release_results['cp'] = True + + release_iv = release_config.get('release_below_iv', 0) + if iv < release_iv: + release_results['iv'] = True + + logic_to_function = { + 'or': lambda x, y: x or y, + 'and': lambda x, y: x and y + } + + #logger.log( + # "Release config for {}: CP {} {} IV {}".format( + # pokemon_name, + # min_cp, + # cp_iv_logic, + # min_iv + # ), 'yellow' + #) + + return logic_to_function[cp_iv_logic](*release_results.values()) def _get_release_config_for(self, pokemon): - release_config = self.config.release_config.get(pokemon) + release_config = self.config.release.get(pokemon) if not release_config: - release_config = self.config.release_config['any'] + release_config = self.config.release['any'] return release_config - - def _get_exceptions(self): - exceptions = self.config.release_config.get('exceptions') - if not exceptions: - return None - return exceptions - - def _get_always_capture_list(self): - exceptions = self._get_exceptions() - if not exceptions: - return [] - always_capture_list = exceptions['always_capture'] - if not always_capture_list: - return [] - return always_capture_list - - def _check_always_capture_exception_for(self, pokemon_name): - always_capture_list = self._get_always_capture_list() - if not always_capture_list: - return False - else: - for pokemon in always_capture_list: - if pokemon_name == str(pokemon): - return True - return False diff --git a/pokemongo_bot/cell_workers/seen_fort_worker.py b/pokemongo_bot/cell_workers/seen_fort_worker.py index a1faafa66d..c5709ad511 100644 --- a/pokemongo_bot/cell_workers/seen_fort_worker.py +++ b/pokemongo_bot/cell_workers/seen_fort_worker.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- -import json import time -from math import radians, sqrt, sin, cos, atan2 -from pgoapi.utilities import f2i, h2f -from utils import print_green, print_yellow, print_red, format_time -from pokemongo_bot.human_behaviour import sleep + +from pgoapi.utilities import f2i + from pokemongo_bot import logger +from pokemongo_bot.human_behaviour import sleep +from utils import format_time class SeenFortWorker(object): @@ -18,7 +18,6 @@ def __init__(self, fort, bot): self.config = bot.config self.item_list = bot.item_list self.rest_time = 50 - self.stepper = bot.stepper def work(self): lat = self.fort['latitude'] @@ -35,8 +34,8 @@ def work(self): fort_name = fort_details['name'].encode('utf8', 'replace') else: fort_name = 'Unknown' - logger.log('[#] Now at Pokestop: ' + fort_name + ' - Spinning...', - 'yellow') + logger.log('Now at Pokestop: ' + fort_name + ' - Spinning...', + 'cyan') sleep(2) self.api.fort_search(fort_id=self.fort['id'], fort_latitude=lat, @@ -49,11 +48,11 @@ def work(self): spin_details = response_dict['responses']['FORT_SEARCH'] if spin_details['result'] == 1: - logger.log("[+] Loot: ", 'green') + logger.log("Loot: ", 'green') experience_awarded = spin_details.get('experience_awarded', False) if experience_awarded: - logger.log("[+] " + str(experience_awarded) + " xp", + logger.log(str(experience_awarded) + " xp", 'green') items_awarded = spin_details.get('items_awarded', False) @@ -69,13 +68,11 @@ def work(self): for item_id, item_count in tmp_count_items.iteritems(): item_name = self.item_list[str(item_id)] - logger.log("[+] " + str(item_count) + - "x " + item_name + - " (Total: " + str(self.bot.item_inventory_count(item_id)) + ")", 'green') + logger.log('- ' + str(item_count) + "x " + item_name + " (Total: " + str(self.bot.item_inventory_count(item_id)) + ")", 'yellow') # RECYCLING UNWANTED ITEMS if str(item_id) in self.config.item_filter: - logger.log("[+] Recycling " + str(item_count) + "x " + item_name + "...", 'green') + logger.log("-- Recycling " + str(item_count) + "x " + item_name + "...", 'green') #RECYCLE_INVENTORY_ITEM response_dict_recycle = self.bot.drop_item(item_id=item_id, count=item_count) @@ -85,9 +82,9 @@ def work(self): 'result' in response_dict_recycle['responses']['RECYCLE_INVENTORY_ITEM']: result = response_dict_recycle['responses']['RECYCLE_INVENTORY_ITEM']['result'] if result is 1: # Request success - logger.log("[+] Recycling success", 'green') + logger.log("-- Recycled " + item_name + "!", 'green') else: - logger.log("[+] Recycling failed!", 'red') + logger.log("-- Recycling " + item_name + "has failed!", 'red') else: logger.log("[#] Nothing found.", 'yellow') @@ -95,7 +92,7 @@ def work(self): 'cooldown_complete_timestamp_ms') if pokestop_cooldown: seconds_since_epoch = time.time() - logger.log('[#] PokeStop on cooldown. Time left: ' + str( + logger.log('PokeStop on cooldown. Time left: ' + str( format_time((pokestop_cooldown / 1000) - seconds_since_epoch))) @@ -115,11 +112,11 @@ def work(self): 'cooldown_complete_timestamp_ms') if pokestop_cooldown: seconds_since_epoch = time.time() - logger.log('[#] PokeStop on cooldown. Time left: ' + str( + logger.log('PokeStop on cooldown. Time left: ' + str( format_time((pokestop_cooldown / 1000) - seconds_since_epoch))) elif spin_details['result'] == 4: - print_red("[#] Inventory is full, switching to catch mode...") + logger.log("Inventory is full, switching to catch mode...", 'red') self.config.mode = 'poke' if 'chain_hack_sequence_number' in response_dict['responses'][ @@ -128,7 +125,7 @@ def work(self): return response_dict['responses']['FORT_SEARCH'][ 'chain_hack_sequence_number'] else: - print_yellow('[#] may search too often, lets have a rest') + logger.log('Possibly searching too often - taking a short rest :)', 'yellow') return 11 sleep(8) return 0 diff --git a/pokemongo_bot/cell_workers/utils.py b/pokemongo_bot/cell_workers/utils.py index bd31375ccc..4d866e6dde 100644 --- a/pokemongo_bot/cell_workers/utils.py +++ b/pokemongo_bot/cell_workers/utils.py @@ -3,9 +3,29 @@ import struct from math import cos, asin, sqrt from colorama import init +from s2sphere import CellId, LatLng init() +def get_cellid(lat, long, radius=10): + origin = CellId.from_lat_lng(LatLng.from_degrees(lat, long)).parent(15) + walk = [origin.id()] + + # 10 before and 10 after + next = origin.next() + prev = origin.prev() + for i in range(radius): + walk.append(prev.id()) + walk.append(next.id()) + next = next.next() + prev = prev.prev() + return sorted(walk) + +def encode(cellid): + output = [] + encoder._VarintEncoder()(output.append, cellid) + return ''.join(output) + def distance(lat1, lon1, lat2, lon2): p = 0.017453292519943295 a = 0.5 - cos((lat2 - lat1) * p) / 2 + cos(lat1 * p) * \ diff --git a/pokemongo_bot/human_behaviour.py b/pokemongo_bot/human_behaviour.py index 6d4c434f92..2da9d1e365 100644 --- a/pokemongo_bot/human_behaviour.py +++ b/pokemongo_bot/human_behaviour.py @@ -1,14 +1,15 @@ # -*- coding: utf-8 -*- import time -from math import ceil -from random import random, randint +from random import random, uniform def sleep(seconds, delta=0.3): - jitter = ceil(delta * seconds) - sleep_time = randint(int(seconds - jitter), int(seconds + jitter)) - time.sleep(sleep_time) + time.sleep(jitter(seconds,delta)) + +def jitter(value, delta=0.3): + jitter = delta * value + return uniform(value-jitter, value+jitter) def random_lat_long_delta(): diff --git a/pokemongo_bot/logger.py b/pokemongo_bot/logger.py index 151e578a0f..636f7e371e 100644 --- a/pokemongo_bot/logger.py +++ b/pokemongo_bot/logger.py @@ -9,14 +9,16 @@ def log(string, color = 'white'): colorHex = { + 'red': '91m', 'green': '92m', 'yellow': '93m', - 'red': '91m' + 'blue': '94m', + 'cyan': '96m' } if color not in colorHex: - print('[' + time.strftime("%Y-%m-%d %H:%M:%S") + '] '+ string) + print('[' + time.strftime("%H:%M:%S") + '] '+ string) else: - print(u'\033['+ colorHex[color] + '[' + time.strftime("%Y-%m-%d %H:%M:%S") + '] ' + string.decode('utf-8') + '\033[0m') + print('[' + time.strftime("%H:%M:%S") + '] ' + u'\033['+ colorHex[color] + string.decode('utf-8') + '\033[0m') if lcd: if(string): lcd.message(string) diff --git a/pokemongo_bot/polyline_stepper.py b/pokemongo_bot/polyline_stepper.py index 32d07fc1c9..1ac25dd9a4 100644 --- a/pokemongo_bot/polyline_stepper.py +++ b/pokemongo_bot/polyline_stepper.py @@ -1,56 +1,43 @@ # -*- coding: utf-8 -*- -from polyline_walker import PolylineWalker +from math import ceil + from stepper import Stepper -from human_behaviour import sleep, random_lat_long_delta + +import logger +from cell_workers.utils import i2f +from human_behaviour import sleep +from polyline_walker import PolylineWalker class PolylineStepper(Stepper): def _walk_to(self, speed, lat, lng, alt): - origin = ','.join([str(self.api._position_lat), str(self.api._position_lng)]) + origin = ','.join([str(i2f(self.api._position_lat)), str(i2f(self.api._position_lng))]) destination = ','.join([str(lat), str(lng)]) - polyline_walker = PolylineWalker(origin, destination, self.speed) + polyline_walker = PolylineWalker(origin, destination, speed) proposed_origin = polyline_walker.points[0] proposed_destination = polyline_walker.points[-1] proposed_lat = proposed_origin[0] proposed_lng = proposed_origin[1] if proposed_lat != lat and proposed_lng != lng: + logger.log('[#] Using _old_walk_to to go to the proposed_origin: {}' + .format(proposed_origin)) self._old_walk_to(speed, proposed_lat, proposed_lng, alt) - while proposed_destination != polyline_walker.get_pos()[0]: - cLat, cLng = polyline_walker.get_pos()[0] - self.api.set_position(cLat, cLng, alt) - self.bot.heartbeat() - self._work_at_position(i2f(self.api._position_lat), i2f(self.api._position_lng), alt, False) - sleep(1) # sleep one second plus a random delta - if proposed_lat != self.api._position_lat and proposed_lng != self.api._position_lng: - self._old_walk_to(speed, lat, lng, alt) - - def _old_walk_to(self, speed, lat, lng, alt): - dist = distance( - i2f(self.api._position_lat), i2f(self.api._position_lng), lat, lng) - steps = (dist + 0.0) / (speed + 0.0) # may be rational number - intSteps = int(steps) - residuum = steps - intSteps - logger.log('[#] Walking from ' + str((i2f(self.api._position_lat), i2f( - self.api._position_lng))) + " to " + str(str((lat, lng))) + - " for approx. " + str(format_time(ceil(steps)))) - if steps != 0: - dLat = (lat - i2f(self.api._position_lat)) / steps - dLng = (lng - i2f(self.api._position_lng)) / steps - - for i in range(intSteps): - cLat = i2f(self.api._position_lat) + \ - dLat + random_lat_long_delta() - cLng = i2f(self.api._position_lng) + \ - dLng + random_lat_long_delta() + if proposed_origin != proposed_destination: + duration = polyline_walker.get_total_distance() / speed + logger.log('[#] Using PolylineWalker from {} to {} for approx. {} seconds.' + .format(proposed_origin, proposed_destination, ceil(duration))) + while proposed_destination != polyline_walker.get_pos()[0]: + cLat, cLng = polyline_walker.get_pos()[0] self.api.set_position(cLat, cLng, alt) self.bot.heartbeat() + self._work_at_position(i2f(self.api._position_lat), i2f(self.api._position_lng), alt, False) sleep(1) # sleep one second plus a random delta - self._work_at_position( - i2f(self.api._position_lat), i2f(self.api._position_lng), - alt, False) + if proposed_lat != self.api._position_lat and proposed_lng != self.api._position_lng: + logger.log('[#] Using _old_walk_to to go from the proposed destination : {} to {}' + .format(proposed_destination, (lat, lng))) - self.api.set_position(lat, lng, alt) - self.bot.heartbeat() - logger.log("[#] Finished walking") + self._old_walk_to(speed, lat, lng, alt) + def _old_walk_to(self, speed, lat, lng, alt): + return super(PolylineStepper, self)._walk_to(speed, lat, lng, alt) diff --git a/pokemongo_bot/polyline_walker/polyline_tester.py b/pokemongo_bot/polyline_walker/polyline_tester.py index fdf547fdd6..a8d0554e16 100644 --- a/pokemongo_bot/polyline_walker/polyline_tester.py +++ b/pokemongo_bot/polyline_walker/polyline_tester.py @@ -1,8 +1,11 @@ import time +from math import ceil + import haversine import polyline -from math import ceil + from polyline_walker import PolylineWalker + a = PolylineWalker('Poststrasse+20,Zug,CH', 'Guggiweg+7,Zug,CH', 100) print('Walking polyline: ', a.polyline) print('Encoded level: ','B'*len(a.points)) diff --git a/pokemongo_bot/polyline_walker/polyline_walker.py b/pokemongo_bot/polyline_walker/polyline_walker.py index e6a92c1c5e..2c5be3daaa 100644 --- a/pokemongo_bot/polyline_walker/polyline_walker.py +++ b/pokemongo_bot/polyline_walker/polyline_walker.py @@ -1,10 +1,12 @@ -import requests -import polyline -import haversine import time -from itertools import chain +from itertools import chain from math import ceil +import haversine +import polyline +import requests + + class PolylineWalker(object): def __init__(self, origin, destination, speed): @@ -85,7 +87,7 @@ def get_pos(self): def calculate_coord(self, percentage, o, d): lat = o[0]+ (d[0] -o[0]) * percentage lon = o[1]+ (d[1] -o[1]) * percentage - return [(round(lat, 5), round(lon, 5))] + return [(lat, lon)] def get_total_distance(self): return ceil(sum([haversine.haversine(*x)*1000 for x in self.walk_steps()])) diff --git a/pokemongo_bot/spiral_navigator.py b/pokemongo_bot/spiral_navigator.py new file mode 100644 index 0000000000..770d609ee9 --- /dev/null +++ b/pokemongo_bot/spiral_navigator.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +import logger +from cell_workers.utils import distance, i2f, format_dist +from human_behaviour import sleep +from step_walker import StepWalker + + +class SpiralNavigator(object): + def __init__(self, bot): + self.bot = bot + self.api = bot.api + self.config = bot.config + + self.pos = 1 + self.x = 0 + self.y = 0 + self.dx = 0 + self.dy = -1 + self.steplimit = self.config.max_steps + self.steplimit2 = self.steplimit**2 + self.origin_lat = self.bot.position[0] + self.origin_lon = self.bot.position[1] + self._step_walker = None + + def take_step(self): + position = (self.origin_lat, self.origin_lon, 0.0) + + logger.log('Scanning area for objects....') + # logger.log('[#] Scanning area for objects ({} / {})'.format( + # (step + 1), self.steplimit**2)) + if self.config.debug: + logger.log( + 'steplimit: {} x: {} y: {} pos: {} dx: {} dy {}'.format( + self.steplimit2, self.x, self.y, self.pos, self.dx, + self.dy)) + # Scan location math + + if -self.steplimit2 / 2 < self.x <= self.steplimit2 / 2 and -self.steplimit2 / 2 < self.y <= self.steplimit2 / 2: + position = (self.x * 0.0025 + self.origin_lat, + self.y * 0.0025 + self.origin_lon, 0) + if self.config.walk > 0: + if not self._step_walker: + self._step_walker = StepWalker( + self.bot, + self.config.walk, + self.api._position_lat, + self.api._position_lng, + position[0], + position[1] + ) + + dist = distance( + i2f(self.api._position_lat), + i2f(self.api._position_lng), + position[0], + position[1] + ) + + logger.log('Walking from ' + str((i2f(self.api._position_lat), i2f( + self.api._position_lng))) + " to " + str((str(position[0:2]))) + " " + format_dist(dist, self.config.distance_unit)) + + if self._step_walker.step(): + self._step_walker = None + else: + self.api.set_position(*position) + if self.x == self.y or self.x < 0 and self.x == -self.y or self.x > 0 and self.x == 1 - self.y: + (self.dx, self.dy) = (-self.dy, self.dx) + + if distance( + i2f(self.api._position_lat), + i2f(self.api._position_lng), + position[0], + position[1] + ) <= 1 or (self.config.walk > 0 and self._step_walker == None): + (self.x, self.y) = (self.x + self.dx, self.y + self.dy) + sleep(1) + return position[0:2] diff --git a/pokemongo_bot/step_walker.py b/pokemongo_bot/step_walker.py new file mode 100644 index 0000000000..23e723b77c --- /dev/null +++ b/pokemongo_bot/step_walker.py @@ -0,0 +1,71 @@ +from math import sqrt + +from cell_workers.utils import distance, i2f +from human_behaviour import random_lat_long_delta, sleep + + +class StepWalker(object): + + def __init__(self, bot, speed, initLat, initLng, destLat, destLng): + self.bot = bot + self.api = bot.api + + dist = distance( + i2f(initLat), + i2f(initLng), + destLat, + destLng + ) + + self.speed = speed + + self.destLat = destLat + self.destLng = destLng + + self.steps = (dist + 0.0) / (speed + 0.0) + + if dist < speed or self.steps < 1: + self.dLat = 0 + self.dLng = 0 + self.magnitude = 0; + else: + self.dLat = (destLat - i2f(initLat)) / self.steps + self.dLng = (destLng - i2f(initLng)) / self.steps + self.magnitude = self._pythagorean(self.dLat, self.dLng) + + def step(self): + dist = distance( + i2f(self.api._position_lat), + i2f(self.api._position_lng), + self.destLat, + self.destLng + ) + # print 'distance' + # print dist + + if (self.dLat == 0 and self.dLng == 0) or dist < self.speed: + self.api.set_position(self.destLat, self.destLng, 0) + return True + + totalDLat = (self.destLat - i2f(self.api._position_lat)) + totalDLng = (self.destLng - i2f(self.api._position_lng)) + magnitude = self._pythagorean(totalDLat, totalDLng) + unitLat = totalDLat / magnitude + unitLng = totalDLng / magnitude + + scaledDLat = unitLat * self.magnitude + scaledDLng = unitLng * self.magnitude + + cLat = i2f(self.api._position_lat) + scaledDLat + random_lat_long_delta() + cLng = i2f(self.api._position_lng) + scaledDLng + random_lat_long_delta() + + self.api.set_position(cLat, cLng, 0) + self.bot.position = (cLat,cLng,0) # set position so we can use it later on + self.bot.heartbeat() + sleep(1) # sleep one second plus a random delta + # self._work_at_position( + # i2f(self.api._position_lat), i2f(self.api._position_lng), + # alt, False) + + def _pythagorean(self, lat, lng): + return sqrt((lat ** 2) + (lng ** 2)) diff --git a/pokemongo_bot/stepper.py b/pokemongo_bot/stepper.py deleted file mode 100644 index fda5e63fb8..0000000000 --- a/pokemongo_bot/stepper.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import json -import time -import pprint - -from math import ceil -from s2sphere import CellId, LatLng -from google.protobuf.internal import encoder - -from human_behaviour import sleep, random_lat_long_delta -from cell_workers.utils import distance, i2f, format_time - -from pgoapi.utilities import f2i, h2f -import logger - - -class Stepper(object): - def __init__(self, bot): - self.bot = bot - self.api = bot.api - self.config = bot.config - - self.pos = 1 - self.x = 0 - self.y = 0 - self.dx = 0 - self.dy = -1 - self.steplimit = self.config.max_steps - self.steplimit2 = self.steplimit**2 - self.origin_lat = self.bot.position[0] - self.origin_lon = self.bot.position[1] - - def take_step(self): - position = (self.origin_lat, self.origin_lon, 0.0) - - self.api.set_position(*position) - for step in range(self.steplimit2): - # starting at 0 index - logger.log('[#] Scanning area for objects ({} / {})'.format( - (step + 1), self.steplimit**2)) - if self.config.debug: - logger.log( - 'steplimit: {} x: {} y: {} pos: {} dx: {} dy {}'.format( - self.steplimit2, self.x, self.y, self.pos, self.dx, - self.dy)) - # Scan location math - if -self.steplimit2 / 2 < self.x <= self.steplimit2 / 2 and -self.steplimit2 / 2 < self.y <= self.steplimit2 / 2: - position = (self.x * 0.0025 + self.origin_lat, - self.y * 0.0025 + self.origin_lon, 0) - if self.config.walk > 0: - self._walk_to(self.config.walk, *position) - else: - self.api.set_position(*position) - print('[#] {}'.format(position)) - if self.x == self.y or self.x < 0 and self.x == -self.y or self.x > 0 and self.x == 1 - self.y: - (self.dx, self.dy) = (-self.dy, self.dx) - - (self.x, self.y) = (self.x + self.dx, self.y + self.dy) - - self._work_at_position(position[0], position[1], position[2], True) - sleep(10) - - def _walk_to(self, speed, lat, lng, alt): - dist = distance( - i2f(self.api._position_lat), i2f(self.api._position_lng), lat, lng) - steps = (dist + 0.0) / (speed + 0.0) # may be rational number - intSteps = int(steps) - residuum = steps - intSteps - logger.log('[#] Walking from ' + str((i2f(self.api._position_lat), i2f( - self.api._position_lng))) + " to " + str(str((lat, lng))) + - " for approx. " + str(format_time(ceil(steps)))) - if steps != 0: - dLat = (lat - i2f(self.api._position_lat)) / steps - dLng = (lng - i2f(self.api._position_lng)) / steps - - for i in range(intSteps): - cLat = i2f(self.api._position_lat) + \ - dLat + random_lat_long_delta() - cLng = i2f(self.api._position_lng) + \ - dLng + random_lat_long_delta() - self.api.set_position(cLat, cLng, alt) - self.bot.heartbeat() - sleep(1) # sleep one second plus a random delta - self._work_at_position( - i2f(self.api._position_lat), i2f(self.api._position_lng), - alt, False) - - self.api.set_position(lat, lng, alt) - self.bot.heartbeat() - logger.log("[#] Finished walking") - - def _work_at_position(self, lat, lng, alt, pokemon_only=False): - cellid = self._get_cellid(lat, lng) - timestamp = [0, ] * len(cellid) - self.api.get_map_objects(latitude=f2i(lat), - longitude=f2i(lng), - since_timestamp_ms=timestamp, - cell_id=cellid) - - response_dict = self.api.call() - # pprint.pprint(response_dict) - # Passing Variables through a file - if response_dict and 'responses' in response_dict: - if 'GET_MAP_OBJECTS' in response_dict['responses']: - if 'map_cells' in response_dict['responses'][ - 'GET_MAP_OBJECTS']: - user_web_location = 'web/location-%s.json' % (self.config.username) - if os.path.isfile(user_web_location): - with open(user_web_location, 'w') as outfile: - json.dump( - {'lat': lat, - 'lng': lng, - 'cells': response_dict[ - 'responses']['GET_MAP_OBJECTS']['map_cells']}, - outfile) - - user_data_lastlocation = 'data/last-location-%s.json' % (self.config.username) - if os.path.isfile(user_data_lastlocation): - with open(user_data_lastlocation, 'w') as outfile: - outfile.truncate() - json.dump({'lat': lat, 'lng': lng}, outfile) - - if response_dict and 'responses' in response_dict: - if 'GET_MAP_OBJECTS' in response_dict['responses']: - if 'status' in response_dict['responses']['GET_MAP_OBJECTS']: - if response_dict['responses']['GET_MAP_OBJECTS'][ - 'status'] is 1: - map_cells = response_dict['responses'][ - 'GET_MAP_OBJECTS']['map_cells'] - position = (lat, lng, alt) - # Sort all by distance from current pos- eventually this should build graph & A* it - # print(map_cells) - #print( s2sphere.from_token(x['s2_cell_id']) ) - map_cells.sort(key=lambda x: distance(lat, lng, x['forts'][0]['latitude'], x[ - 'forts'][0]['longitude']) if 'forts' in x and x['forts'] != [] else 1e6) - for cell in map_cells: - self.bot.work_on_cell(cell, position, pokemon_only) - - def _get_cellid(self, lat, long, radius=10): - origin = CellId.from_lat_lng(LatLng.from_degrees(lat, long)).parent(15) - walk = [origin.id()] - - # 10 before and 10 after - next = origin.next() - prev = origin.prev() - for i in range(radius): - walk.append(prev.id()) - walk.append(next.id()) - next = next.next() - prev = prev.prev() - return sorted(walk) - - def _encode(self, cellid): - output = [] - encoder._VarintEncoder()(output.append, cellid) - return ''.join(output) diff --git a/travis-pythoncheck.py b/pylint-recursive.py similarity index 55% rename from travis-pythoncheck.py rename to pylint-recursive.py index 1095b04a12..2ced31db96 100644 --- a/travis-pythoncheck.py +++ b/pylint-recursive.py @@ -1,33 +1,37 @@ #! /usr/bin/env python ''' +Author: gregorynicholas (github), modified by Jacob Henderson (jacohend, github) Module that runs pylint on all python scripts found in a directory tree.. -''' +''' import os import re import sys -total = 0.0 -count = 0 +passed = 0 +failed = 0 +errors = list() def check(module): + global passed, failed ''' apply pylint to the file specified if it is a *.py file ''' - global total, count - if module[-3:] == ".py": - + print "CHECKING ", module pout = os.popen('pylint %s'% module, 'r') for line in pout: - if re.match("E....:.", line): - print line if "Your code has been rated at" in line: - print line - score = re.findall("\d.\d\d", line)[0] - total += float(score) - count += 1 + print "PASSED pylint inspection: " + line + passed += 1 + return True + if "-error" in line: + print "FAILED pylint inspection: " + line + failed += 1 + errors.append("FILE: " + module) + errors.append("FAILED pylint inspection: " + line) + return False if __name__ == "__main__": try: @@ -36,13 +40,18 @@ def check(module): except IndexError: print "no directory specified, defaulting to current working directory" BASE_DIRECTORY = os.getcwd() + print "looking for *.py scripts in subdirectories of ", BASE_DIRECTORY for root, dirs, files in os.walk(BASE_DIRECTORY): for name in files: filepath = os.path.join(root, name) check(filepath) - - print "==" * 50 - print "%d modules found"% count - print "AVERAGE SCORE = %.02f"% (total / count) \ No newline at end of file + print "Passed: " + str(passed) + " Failed: " + str(failed) + print "\n" + print "Showing errors:" + if (str(failed)): + for err in errors: + print err + + sys.exit("Pylint failed with errors") diff --git a/release_config.json.example b/release_config.json.example deleted file mode 100644 index 06d4687e9a..0000000000 --- a/release_config.json.example +++ /dev/null @@ -1,174 +0,0 @@ -{ - "any": { - "release_under_cp": 400, - "release_under_iv": 0.9, - "cp_iv_logic": "and" - }, - - "Bulbasaur": { "release_under_cp": 374, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Ivysaur": { "release_under_cp": 571, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Venusaur": { "release_under_cp": 902, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Charmander": { "release_under_cp": 333, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Charmeleon": { "release_under_cp": 544, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Charizard": { "release_under_cp": 909, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Squirtle": { "release_under_cp": 352, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Wartortle": { "release_under_cp": 552, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Blastoise": { "release_under_cp": 888, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Caterpie": { "release_under_cp": 156, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Metapod": { "release_under_cp": 168, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Butterfree": { "release_under_cp": 508, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Weedle": { "release_under_cp": 156, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kakuna": { "release_under_cp": 170, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Beedrill": { "release_under_cp": 504, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Pidgey": { "release_under_cp": 237, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Pidgeotto": { "release_under_cp": 427, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Pidgeot": { "release_under_cp": 729, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Rattata": { "release_under_cp": 204, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Raticate": { "release_under_cp": 504, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Spearow": { "release_under_cp": 240, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Fearow": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Ekans": { "release_under_cp": 288, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Arbok": { "release_under_cp": 616, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Pikachu": { "release_under_cp": 309, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Raichu": { "release_under_cp": 708, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Sandshrew": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Sandslash": { "release_under_cp": 631, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidoran F": { "release_under_cp": 304, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidorina": { "release_under_cp": 489, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidoqueen": { "release_under_cp": 868, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidoran M": { "release_under_cp": 295, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidorino": { "release_under_cp": 480, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Nidoking": { "release_under_cp": 864, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Clefairy": { "release_under_cp": 420, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Clefable": { "release_under_cp": 837, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Vulpix": { "release_under_cp": 290, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Ninetales": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Jigglypuff": { "release_under_cp": 321, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Wigglytuff": { "release_under_cp": 760, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Zubat": { "release_under_cp": 225, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Golbat": { "release_under_cp": 672, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Oddish": { "release_under_cp": 400, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Gloom": { "release_under_cp": 590, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Vileplume": { "release_under_cp": 871, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Paras": { "release_under_cp": 319, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Parasect": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Venonat": { "release_under_cp": 360, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Venomoth": { "release_under_cp": 660, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Diglett": { "release_under_cp": 158, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dugtrio": { "release_under_cp": 408, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Meowth": { "release_under_cp": 264, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Persian": { "release_under_cp": 568, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Psyduck": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Golduck": { "release_under_cp": 832, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Mankey": { "release_under_cp": 307, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Primeape": { "release_under_cp": 650, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Growlithe": { "release_under_cp": 465, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Arcanine": { "release_under_cp": 1041, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Poliwag": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Poliwhirl": { "release_under_cp": 468, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Poliwrath": { "release_under_cp": 876, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Abra": { "release_under_cp": 208, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kadabra": { "release_under_cp": 396, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Alakazam": { "release_under_cp": 633, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Machop": { "release_under_cp": 381, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Machoke": { "release_under_cp": 614, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Machamp": { "release_under_cp": 907, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Bellsprout": { "release_under_cp": 391, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Weepinbell": { "release_under_cp": 602, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Victreebel": { "release_under_cp": 883, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Tentacool": { "release_under_cp": 316, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Tentacruel": { "release_under_cp": 775, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Geodude": { "release_under_cp": 297, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Graveler": { "release_under_cp": 501, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Golem": { "release_under_cp": 804, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Ponyta": { "release_under_cp": 530, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Rapidash": { "release_under_cp": 768, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Slowpoke": { "release_under_cp": 424, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Slowbro": { "release_under_cp": 907, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Magnemite": { "release_under_cp": 312, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Magneton": { "release_under_cp": 657, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Farfetch'd": { "release_under_cp": 441, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Doduo": { "release_under_cp": 297, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dodrio": { "release_under_cp": 640, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Seel": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dewgong": { "release_under_cp": 748, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Grimer": { "release_under_cp": 448, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Muk": { "release_under_cp": 909, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Shellder": { "release_under_cp": 288, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Cloyster": { "release_under_cp": 717, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Gastly": { "release_under_cp": 280, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Haunter": { "release_under_cp": 482, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Gengar": { "release_under_cp": 724, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Onix": { "release_under_cp": 300, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Drowzee": { "release_under_cp": 374, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Hypno": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Krabby": { "release_under_cp": 276, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kingler": { "release_under_cp": 636, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Voltorb": { "release_under_cp": 292, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Electrode": { "release_under_cp": 576, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Exeggcute": { "release_under_cp": 384, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Exeggutor": { "release_under_cp": 1032, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Cubone": { "release_under_cp": 352, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Marowak": { "release_under_cp": 578, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Hitmonlee": { "release_under_cp": 520, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Hitmonchan": { "release_under_cp": 530, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Lickitung": { "release_under_cp": 568, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Koffing": { "release_under_cp": 403, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Weezing": { "release_under_cp": 784, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Rhyhorn": { "release_under_cp": 412, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Rhydon": { "release_under_cp": 782, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Chansey": { "release_under_cp": 235, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Tangela": { "release_under_cp": 607, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kangaskhan": { "release_under_cp": 712, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Horsea": { "release_under_cp": 278, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Seadra": { "release_under_cp": 597, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Goldeen": { "release_under_cp": 336, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Seaking": { "release_under_cp": 712, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Staryu": { "release_under_cp": 326, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Starmie": { "release_under_cp": 763, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Mr. Mime": { "release_under_cp": 520, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Scyther": { "release_under_cp": 724, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Jynx": { "release_under_cp": 600, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Electabuzz": { "release_under_cp": 739, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Magmar": { "release_under_cp": 792, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Pinsir": { "release_under_cp": 741, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Tauros": { "release_under_cp": 643, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Magikarp": { "release_under_cp": 91, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Gyarados": { "release_under_cp": 938, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Lapras": { "release_under_cp": 1041, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Ditto": { "release_under_cp": 321, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Eevee": { "release_under_cp": 376, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Vaporeon": { "release_under_cp": 984, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Jolteon": { "release_under_cp": 746, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Flareon": { "release_under_cp": 924, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Porygon": { "release_under_cp": 590, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Omanyte": { "release_under_cp": 391, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Omastar": { "release_under_cp": 780, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kabuto": { "release_under_cp": 386, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Kabutops": { "release_under_cp": 744, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Aerodactyl": { "release_under_cp": 756, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Snorlax": { "release_under_cp": 1087, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Articuno": { "release_under_cp": 1039, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Zapdos": { "release_under_cp": 1087, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Moltres": { "release_under_cp": 1132, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dratini": { "release_under_cp": 343, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dragonair": { "release_under_cp": 609, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Dragonite": { "release_under_cp": 1221, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Mewtwo": { "release_under_cp": 1447, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - "Mew": { "release_under_cp": 1152, "release_under_iv": 0.8, "cp_iv_logic": "and" }, - - "exceptions": { - "always_capture": [ - "Arcanine", - "Lapras", - "Dragonite", - "Snorlax", - "Blastoise", - "Moltres", - "Articuno", - "Zapdos", - "Mew", - "Mewtwo" - ] - } -} diff --git a/web b/web index dc742c598a..83463c2bcd 160000 --- a/web +++ b/web @@ -1 +1 @@ -Subproject commit dc742c598a2636337bd358dae8a558ef02159e8e +Subproject commit 83463c2bcd5c4360adbc41c61e6572406fec54ce