├── .editorconfig
├── .eslintrc
├── .gitignore
├── ExampleInventory.js
├── ExamplePromises.js
├── ExampleStats.js
├── LICENSE.md
├── README.md
├── auth.js
├── example.js
├── exampleFort.js
├── exampleStats.js
├── logins.js
├── package.json
├── poke.io.js
├── pokego.js
├── pokemon.proto
├── pokemons.json
└── tests
└── poke.io
├── GetLocation.js
├── GetLocationCoords.js
└── SetLocation.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | insert_final_newline = true
5 | trim_trailing_whitespace = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [package.json]
11 | indent_style = space
12 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "indent": [
4 | 1,
5 | 4,
6 | {"SwitchCase": 1}
7 | ],
8 | "quotes": [
9 | 2,
10 | "single"
11 | ],
12 | "semi": [
13 | 2,
14 | "always"
15 | ],
16 | "comma-dangle": [
17 | 0,
18 | "always-multiline"
19 | ],
20 | "no-console": [
21 | 0,
22 | ],
23 | "no-unused-vars": [
24 | 1,
25 | ]
26 | },
27 | "env": {
28 | "node": true,
29 | "es6": true
30 | },
31 | "extends": "eslint:recommended"
32 | }
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directory
2 | node_modules
3 |
4 | # Istanbul coverage report
5 | coverage
6 |
7 | # My tests
8 | derek
9 |
--------------------------------------------------------------------------------
/ExampleInventory.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var username = process.env.PGO_USERNAME || 'username';
4 | var password = process.env.PGO_PASSWORD || 'password';
5 | var provider = process.env.PGO_PROVIDER || 'google'; /* google OR ptc */
6 |
7 | var location = {
8 | type: 'name',
9 | name: process.env.PGO_LOCATION || 'Time Square'
10 |
11 | // type: 'coords',
12 | // coords: {
13 | // latitude: 40.758896,
14 | // longitude: -73.985130,
15 | // altitude: 10
16 | // }
17 |
18 | };
19 |
20 | var Pokego = require('./pokego.js');
21 | var util = require('util');
22 | util.inspect(console, true);
23 |
24 | Pokego.init(username, password, location, provider).then((profile) => {
25 | return new Promise(function(resolve, reject) {
26 | Pokego.GetProfile().then((profile) => {
27 | return Pokego.formatPlayercard(profile);
28 | }).then((val) => {
29 | Pokego.GetInventory().then((profile) => {
30 | Pokego.displayInventory(profile);
31 | });
32 | }).catch((val) => {
33 | console.log(val);
34 | });
35 | }).then((a) => {console.log(a);});
36 | });
--------------------------------------------------------------------------------
/ExamplePromises.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var username = process.env.PGO_USERNAME || 'username';
4 | var password = process.env.PGO_PASSWORD || 'password';
5 | var provider = process.env.PGO_PROVIDER || 'google'; /* google OR ptc */
6 | var pokeBall = process.env.PGO_POKEBALL || 'POKE_BALL'; // POKE_BALL or GREAT_BALL or ULTRA_BALL
7 |
8 | var location = {
9 | type: 'name',
10 | name: process.env.PGO_LOCATION || 'Time Square'
11 |
12 | // type: 'coords',
13 | // coords: {
14 | // latitude: 40.758896,
15 | // longitude: -73.985130,
16 | // altitude: 10
17 | // }
18 |
19 | };
20 |
21 | var Pokego = require('./pokego.js');
22 | var util = require('util');
23 | util.inspect(console, true);
24 |
25 | var shouldLoop = true;
26 |
27 | Pokego.init(username, password, location, provider).then((profile) => {
28 | setInterval(function() {
29 | return new Promise(function(resolve, reject) {
30 | if(shouldLoop) {
31 | Pokego.GetProfile().then((profile) => {
32 | return Pokego.formatPlayercard(profile);
33 | })
34 | .then((val) => {
35 | Pokego.Heartbeat().then((heart) => {
36 | console.log('[o] pump...');
37 | for (var i = heart.cells.length - 1; i >= 0; i--) {
38 | if(heart.cells[i].WildPokemon[0]) {
39 | shouldLoop = false;
40 | for (var x = heart.cells[i].WildPokemon.length - 1; x >= 0; x--) {
41 | var currentPokemon = heart.cells[i].WildPokemon[x];
42 | var pokemon = Pokego.pokemonlist[parseInt(currentPokemon.pokemon.PokemonId)-1];
43 | console.log('[+] There is a catchable ' + pokemon.name + ' - ' + parseInt(currentPokemon.TimeTillHiddenMs) / 1000 + ' seconds until hidden.');
44 | Pokego.fireAndForgetCatch(currentPokemon, pokemon.name, x, pokeBall).then((data) => {
45 | if(data == 0) {
46 | shouldLoop = true;
47 | resolve('');
48 | }
49 | });
50 | }
51 | }
52 | }
53 | Pokego.changePosition();
54 | }).catch((err) => {console.log(err); });
55 | });
56 | } else {
57 | resolve('[p] Looping stalled to complete execution of task..');
58 | }
59 | }).then((a) => {console.log(a);});
60 | }, 5000);
61 | });
--------------------------------------------------------------------------------
/ExampleStats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var username = process.env.PGO_USERNAME || 'username';
4 | var password = process.env.PGO_PASSWORD || 'password';
5 | var provider = process.env.PGO_PROVIDER || 'google'; /* google OR ptc */
6 |
7 | var location = {
8 | type: 'name',
9 | name: process.env.PGO_LOCATION || 'Time Square'
10 |
11 | // type: 'coords',
12 | // coords: {
13 | // latitude: 40.758896,
14 | // longitude: -73.985130,
15 | // altitude: 10
16 | // }
17 |
18 | };
19 |
20 | var Pokego = require('./pokego.js');
21 | var util = require('util');
22 | util.inspect(console, true);
23 |
24 | Pokego.init(username, password, location, provider).then((profile) => {
25 | Pokego.GetProfile().then((profile) => {
26 | return Pokego.formatPlayercard(profile);
27 | }).then((x) => {
28 | Pokego.getStats().then((stats) => {
29 | console.log(stats);
30 | });
31 | }).catch((val) => {
32 | console.log(val);
33 | });
34 | });
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Arm4x
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PokeGo
2 | Pokemon GO api node.js library, still WIP
3 | Check `ExamplePromises.js`, `example.js`, and `exampleFort.js` for examples
4 |
5 | ## Installation & Usage:
6 | ```git
7 | $ git clone git@github.com:d-pollard/Pokemon-GO-node-api.git .
8 | ```
9 |
10 | ```javascript
11 | var Pokeio = require('./poke.io.js'); // when using poke.io.js
12 | var Pokego = require('./pokego.js'); // when using pokego.js
13 | ```
14 | Check [ExamplePromises.js](./ExamplePromises.js) for the result showed in the demo or check the documentation below.
15 |
16 | ## Demo:
17 | 
18 |
19 | ## Documentation:
20 |
21 | ### Pokeio.init(username, password, location, provider, callback)
22 |
23 | Initializes Pokeio with either pokemon trainer club credentials or google account.
24 | Accepts locations by name or coordinates
25 |
26 | **Parameters**
27 | * `username {String}` Your pokemon trainer club or google username
28 | * `password {String}` Your pokemon trainer club or google password
29 | * `location {Object}` location accepts a combination of type = 'name' & name or type = 'coords' & latitude, longitude, altitude
30 | * `type {String}` Must be one of ['name', 'coords']
31 | * `name {String}` Address for lookup using the google maps api.
32 | * `coords {Object}`
33 | * `latitude {Number}`
34 | * `longitude {Number}`
35 | * `altitude {Number}`
36 | * `provider {String}` Must be one of ['ptc', 'google']
37 | * `callback {Function(error)}`
38 | * `error {Error}`
39 |
40 | ### Pokeio.GetAccessToken(username, password, callback)
41 |
42 | Will save the access token to the Pokeio internal state.
43 |
44 | **Parameters**
45 | * `username {String}` Your pokemon trainer club username
46 | * `password {String}` Your pokemon trainer club password
47 | * `callback {Function(error, token)}`
48 | * `error {Error}`
49 | * `token {String}`
50 |
51 | ### Pokeio.GetApiEndpoint(callback)
52 |
53 | Will save the api endpoint to the Pokeio internal state.
54 |
55 | **Parameters**
56 | * `callback {Function(error, api_endpoint)}`
57 | * `error {Error}`
58 | * `api_endpoint {String}`
59 |
60 | ### Pokeio.GetProfile(callback)
61 | **Parameters**
62 | * `callback {Function(error, profile)}`
63 | * `error {Error}`
64 | * `profile {Object}`
65 | * `creation_time {Number}`
66 | * `username {String}`
67 | * `team {Number}`
68 | * `tutorial {Number/Boolean}`
69 | * `poke_storage {String}`
70 | * `item_storage {String}`
71 | * `daily_bonus {Object}`
72 | * `NextCollectTimestampMs {Number}`
73 | * `NextDefenderBonusCollectTimestampMs {Number}`
74 | * `currency {Object}`
75 | * `type {String}`
76 | * `amount {Number}`
77 |
78 | ### Pokeio.GetLocation(callback)
79 | Reads current latitude and longitude and returns a human readable address using the google maps api.
80 |
81 | **Parameters**
82 | * `callback {Function(error, formatted_address)}`
83 | * `error {Error}`
84 | * `formatted_address {String}`
85 |
86 | ### Pokeio.GetLocationCoords()
87 | **Returns**
88 | * `coordinates {Object}`
89 | * `latitude {Number}`
90 | * `longitude {Number}`
91 | * `altitude {Number}`
92 |
93 | ### Pokeio.SetLocation(location, callback)
94 |
95 | Will save cooridinates to the Pokeio internal state.
96 | Accepts raw coordinates or location name based on the type property.
97 |
98 | **Parameters**
99 | * `location {Object}`
100 | * `type {String}` One of ['name', 'coords']
101 | * `name {String}` Address for lookup using the google maps api.
102 | * `latitude {Number}`
103 | * `longitude {Number}`
104 | * `altitude {Number}`
105 | * `callback {Function(error, coordinates)}`
106 | * `error {Error}`
107 | * `coordinates {Object}`
108 | * `latitude {Number}`
109 | * `longitude {Number}`
110 | * `altitude {Number}`
111 |
112 | ## Thanks to:
113 | Python demo: [tejado](https://github.com/tejado/pokemongo-api-demo)
114 | ES5 demo: [Armax](https://github.com/Armax/Pokemon-GO-node-api/)
115 |
116 |
117 | ## Contact me
118 | [@Derek](mailto:derek@heroesplay.com)
119 | Feel free to contact me for help or anything else
120 |
--------------------------------------------------------------------------------
/auth.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var login_url = 'https://sso.pokemon.com/sso/login?service=https%3A%2F%2Fsso.pokemon.com%2Fsso%2Foauth2.0%2FcallbackAuthorize';
4 | var login_oauth = 'https://sso.pokemon.com/sso/oauth2.0/accessToken';
5 |
6 | // Google Parts
7 | var android_id = '9774d56d682e549c';
8 | var oauth_service = 'audience:server:client_id:848232511240-7so421jotr2609rmqakceuu1luuq0ptb.apps.googleusercontent.com';
9 | var app = 'com.nianticlabs.pokemongo';
10 | var client_sig = '321187995bc7cdc2b5fc91b11a96e2baa8602c62';
11 |
12 | module.exports = {
13 | PokemonClub: function (user, pass, self) {
14 | return new Promise(function(resolve, reject) {
15 | var options = {
16 | url: login_url,
17 | headers: {
18 | 'User-Agent': 'niantic'
19 | }
20 | };
21 |
22 | self.request.get(options, function (err, response, body) {
23 | var data;
24 |
25 | if (err) {
26 | return reject(err);
27 | }
28 | try {
29 | data = JSON.parse(body);
30 | } catch(e) {
31 | return reject(e);
32 | }
33 |
34 | options = {
35 | url: login_url,
36 | form: {
37 | 'lt': data.lt,
38 | 'execution': data.execution,
39 | '_eventId': 'submit',
40 | 'username': user,
41 | 'password': pass
42 | },
43 | headers: {
44 | 'User-Agent': 'niantic'
45 | }
46 | };
47 |
48 | self.request.post(options, function (err, response, body) {
49 | //Parse body if any exists, callback with errors if any.
50 | if(err) {
51 | return reject(err);
52 | }
53 |
54 | if (body) {
55 | var parsedBody = JSON.parse(body);
56 | if (parsedBody.errors && parsedBody.errors.length !== 0) {
57 | return reject('Error logging in: ' + parsedBody.errors[0]);
58 | }
59 | }
60 |
61 | var ticket = response.headers['location'].split('ticket=')[1];
62 |
63 | options = {
64 | url: login_oauth,
65 | form: {
66 | 'client_id': 'mobile-app_pokemon-go',
67 | 'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
68 | 'client_secret': 'w8ScCUXJQc6kXKw8FiOhd8Fixzht18Dq3PEVkUCP5ZPxtgyWsbTvWHFLm2wNY0JR',
69 | 'grant_type': 'refresh_token',
70 | 'code': ticket
71 | },
72 | headers: {
73 | 'User-Agent': 'niantic'
74 | }
75 | };
76 |
77 | self.request.post(options, function (err, response, body) {
78 | var token;
79 |
80 | if(err) {
81 | return reject(err);
82 | }
83 |
84 | // console.log(body);
85 |
86 | try {
87 | token = body.split('token=')[1];
88 | token = token.split('&')[0];
89 | } catch(e) {
90 | return reject('[x] Either the PTC servers are down OR your login information is wrong');
91 | }
92 |
93 | var expiry = body.split('token=')[1].split('&expires=')[1];
94 |
95 | if (!token) {
96 | return reject('Login failed');
97 | }
98 |
99 | self.DebugPrint('[i] Session token: ' + token);
100 | return resolve([token, expiry]);
101 | });
102 |
103 | });
104 |
105 | });
106 | });
107 | },
108 | GoogleAccount: function (user, pass, self) {
109 | return new Promise(function(resolve, reject) {
110 | self.google.login(user, pass, android_id, function (err, data) {
111 | if (data) {
112 | self.google.oauth(user, data.masterToken, data.androidId, oauth_service, app, client_sig, function (err, data) {
113 | if (err) {
114 | return reject(err);
115 | }
116 | return resolve([data.Auth, data.Expiry]);
117 | });
118 | }
119 | else {
120 | return reject(err);
121 | }
122 | });
123 | });
124 | }
125 | };
126 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | var Pokeio = require('./poke.io.js');
2 | var util = require('util');
3 | util.inspect(console, true);
4 |
5 | var username = process.env.PGO_USERNAME || 'username';
6 | var password = process.env.PGO_PASSWORD || 'password';
7 | var provider = process.env.PGO_PROVIDER || 'google';
8 |
9 | var location = {
10 | type: 'name',
11 | name: process.env.PGO_LOCATION || 'Time Square'
12 |
13 | // type: 'coords',
14 | // coords: {
15 | // latitude: 40.758896,
16 | // longitude: -73.985130,
17 | // altitude: 10
18 | // }
19 |
20 | };
21 |
22 | Pokeio.init(username, password, location, provider, function(err) {
23 |
24 | console.log('[i] Current location: ' + Pokeio.playerInfo.locationName);
25 |
26 | console.log('[i] lat/long/alt: : ' + Pokeio.playerInfo.latitude + ' ' + Pokeio.playerInfo.longitude + ' ' + Pokeio.playerInfo.altitude);
27 |
28 | Pokeio.GetProfile(function(err, profile) {
29 | if (err) throw err;
30 |
31 | console.log('[i] Username: ' + profile.username);
32 | console.log('[i] Poke Storage: ' + profile.poke_storage);
33 | console.log('[i] Item Storage: ' + profile.item_storage);
34 |
35 | var poke = 0;
36 | if (profile.currency[0].amount) {
37 | poke = profile.currency[0].amount;
38 | }
39 |
40 | console.log('[i] Pokecoin: ' + poke);
41 | console.log('[i] Stardust: ' + profile.currency[1].amount);
42 |
43 | setInterval(function() {
44 | // This will let you know the heartbeat is pumping..
45 | console.log('[o] pump...');
46 | Pokeio.Heartbeat(function(a,hb) {
47 | if(a !== null) {
48 | console.log('There appeared to be an error...');
49 | } else {
50 | for (var i = hb.cells.length - 1; i >= 0; i--) {
51 |
52 | if(hb.cells[i].WildPokemon[0]) {
53 | for (var x = hb.cells[i].WildPokemon.length - 1; x >= 0; x--) {
54 | var currentPokemon = hb.cells[i].WildPokemon[x];
55 | var iPokedex = Pokeio.pokemonlist[parseInt(currentPokemon.pokemon.PokemonId)-1];
56 | Pokeio.EncounterPokemon(currentPokemon, function(suc, dat) {
57 | console.log('Encountering pokemon ' + iPokedex.name + '...');
58 | Pokeio.CatchPokemon(currentPokemon, 2, function(xsuc, xdat) {
59 | var status = ['Unexpected error', 'Successful catch', 'Catch Escape', 'Catch Flee', 'Missed Catch'];
60 | console.log(status[xdat.Status]);
61 | Pokeio.changePosition();
62 | });
63 | });
64 | }
65 | }
66 | }
67 | // console.log(util.inspect(hb, showHidden=false, depth=10, colorize=true));
68 | }
69 | });
70 | }, 5000);
71 |
72 | });
73 |
74 | });
--------------------------------------------------------------------------------
/exampleFort.js:
--------------------------------------------------------------------------------
1 | var Pokeio = require('./poke.io.js');
2 | var util = require('util');
3 | util.inspect(console, true);
4 |
5 | var username = process.env.PGO_USERNAME || 'username';
6 | var password = process.env.PGO_PASSWORD || 'password';
7 | var provider = process.env.PGO_PROVIDER || 'google';
8 |
9 | var location = {
10 | type: 'name',
11 | name: process.env.PGO_LOCATION || 'Time Square'
12 |
13 | // type: 'coords',
14 | // coords: {
15 | // latitude: 40.758896,
16 | // longitude: -73.985130,
17 | // altitude: 10
18 | // }
19 |
20 | };
21 |
22 | Pokeio.init(username, password, location, provider, function(err) {
23 |
24 | console.log('[i] Current location: ' + Pokeio.playerInfo.locationName);
25 |
26 | console.log('[i] lat/long/alt: : ' + Pokeio.playerInfo.latitude + ' ' + Pokeio.playerInfo.longitude + ' ' + Pokeio.playerInfo.altitude);
27 |
28 | Pokeio.GetProfile(function(err, profile) {
29 | if (err) throw err;
30 |
31 | console.log('[i] Username: ' + profile.username);
32 | console.log('[i] Poke Storage: ' + profile.poke_storage);
33 | console.log('[i] Item Storage: ' + profile.item_storage);
34 |
35 | var poke = 0;
36 | if (profile.currency[0].amount) {
37 | poke = profile.currency[0].amount;
38 | }
39 |
40 | console.log('[i] Pokecoin: ' + poke);
41 | console.log('[i] Stardust: ' + profile.currency[1].amount);
42 |
43 | var fortArr = [];
44 |
45 | setInterval(function() {
46 | // This lets you know the heartbeat is pumping
47 | console.log('[o] pump...');
48 | Pokeio.Heartbeat(function(a,hb) {
49 | if(a !== null) {
50 | console.log('There appeared to be an error...');
51 | } else {
52 | for (var i = hb.cells.length - 1; i >= 0; i--) {
53 | if(hb.cells[i].Fort) {
54 | var currentFortArr = hb.cells[i].Fort;
55 | for (var j = currentFortArr.length - 1; j >= 0; j--) {
56 | var currentFort = currentFortArr[j];
57 | // console.log(currentFort);
58 | if(currentFort.FortType === 1) {
59 | // "Fort" is a pokestop
60 | if(fortArr.indexOf(currentFort.FortId) === -1) {
61 | fortArr.push(currentFort.FortId);
62 | Pokeio.GetFort(currentFort.FortId, currentFort.Latitude, currentFort.Longitude, function(a,b) {
63 | // NO_RESULT_SET = 0; SUCCESS = 1; OUT_OF_RANGE = 2; IN_COOLDOWN_PERIOD = 3; INVENTORY_FULL = 4;
64 | var resultSet = ['Unexpected Error','Successful collect','Out of range','Already collected','Inventory Full'];
65 | if(b.result === 2) {
66 | Pokeio.warpSpeed(currentFort.Latitude, currentFort.Longitude);
67 | Pokeio.Heartbeat(function(z,y) {
68 | Pokeio.GetFort(currentFort.FortId, currentFort.Latitude, currentFort.Longitude, function(a,b) {
69 | console.log('Stop status: ' + resultSet[b.result]);
70 | });
71 | });
72 |
73 | } else {
74 | console.log('Stop status: ' + resultSet[b.result]);
75 | }
76 | console.log(util.inspect(b, showHidden=false, depth=10, colorize=true));
77 | });
78 | }
79 |
80 | } else {
81 | // "Fort" is a gym
82 | if(fortArr.indexOf(currentFort.FortId) === -1) {
83 | fortArr.push(currentFort.FortId);
84 | console.log('.:Fort is a gym, pass:.');
85 | }
86 | }
87 | }
88 | }
89 | }
90 | }
91 | });
92 | }, 5000);
93 |
94 | });
95 |
96 | });
--------------------------------------------------------------------------------
/exampleStats.js:
--------------------------------------------------------------------------------
1 | var Pokeio = require('./poke.io.js');
2 | var util = require('util');
3 | util.inspect(console, true);
4 |
5 | var username = process.env.PGO_USERNAME || 'username';
6 | var password = process.env.PGO_PASSWORD || 'password';
7 | var provider = process.env.PGO_PROVIDER || 'google';
8 |
9 | var location = {
10 | type: 'name',
11 | name: process.env.PGO_LOCATION || 'Time Square'
12 |
13 | // type: 'coords',
14 | // coords: {
15 | // latitude: 40.758896,
16 | // longitude: -73.985130,
17 | // altitude: 10
18 | // }
19 |
20 | };
21 |
22 | Pokeio.init(username, password, location, provider, function(err) {
23 |
24 | console.log('[i] Current location: ' + Pokeio.playerInfo.locationName);
25 |
26 | console.log('[i] lat/long/alt: : ' + Pokeio.playerInfo.latitude + ' ' + Pokeio.playerInfo.longitude + ' ' + Pokeio.playerInfo.altitude);
27 |
28 | Pokeio.GetProfile(function(err, profile) {
29 | if (err) throw err;
30 |
31 | console.log('[i] Username: ' + profile.username);
32 | console.log('[i] Poke Storage: ' + profile.poke_storage);
33 | console.log('[i] Item Storage: ' + profile.item_storage);
34 |
35 | var poke = 0;
36 | if (profile.currency[0].amount) {
37 | poke = profile.currency[0].amount;
38 | }
39 |
40 | console.log('[i] Pokecoin: ' + poke);
41 | console.log('[i] Stardust: ' + profile.currency[1].amount);
42 |
43 | Pokeio.GetStats(function(success, data) {
44 | if(success === null) {
45 | console.log(data);
46 | } else {
47 | console.log('[x] There appeared to be an error!');
48 | }
49 | });
50 |
51 | });
52 |
53 | });
--------------------------------------------------------------------------------
/logins.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var login_url = 'https://sso.pokemon.com/sso/login?service=https%3A%2F%2Fsso.pokemon.com%2Fsso%2Foauth2.0%2FcallbackAuthorize';
4 | var login_oauth = 'https://sso.pokemon.com/sso/oauth2.0/accessToken';
5 |
6 | // Google Parts
7 | var android_id = '9774d56d682e549c';
8 | var oauth_service = 'audience:server:client_id:848232511240-7so421jotr2609rmqakceuu1luuq0ptb.apps.googleusercontent.com';
9 | var app = 'com.nianticlabs.pokemongo';
10 | var client_sig = '321187995bc7cdc2b5fc91b11a96e2baa8602c62';
11 |
12 | module.exports = {
13 | PokemonClub: function (user, pass, self, callback) {
14 | var options = {
15 | url: login_url,
16 | headers: {
17 | 'User-Agent': 'niantic'
18 | }
19 | };
20 |
21 | self.request.get(options, function (err, response, body) {
22 | var data;
23 |
24 | if (err) {
25 | return callback(err, null);
26 | }
27 | data = JSON.parse(body);
28 |
29 | options = {
30 | url: login_url,
31 | form: {
32 | 'lt': data.lt,
33 | 'execution': data.execution,
34 | '_eventId': 'submit',
35 | 'username': user,
36 | 'password': pass
37 | },
38 | headers: {
39 | 'User-Agent': 'niantic'
40 | }
41 | };
42 |
43 | self.request.post(options, function (err, response, body) {
44 | //Parse body if any exists, callback with errors if any.
45 | if(err) {
46 | return callback(err, null);
47 | }
48 |
49 | if (body) {
50 | var parsedBody = JSON.parse(body);
51 | if (parsedBody.errors && parsedBody.errors.length !== 0) {
52 | return callback(new Error('Error logging in: ' + parsedBody.errors[0]), null);
53 | }
54 | }
55 |
56 | var ticket = response.headers['location'].split('ticket=')[1];
57 |
58 | options = {
59 | url: login_oauth,
60 | form: {
61 | 'client_id': 'mobile-app_pokemon-go',
62 | 'redirect_uri': 'https://www.nianticlabs.com/pokemongo/error',
63 | 'client_secret': 'w8ScCUXJQc6kXKw8FiOhd8Fixzht18Dq3PEVkUCP5ZPxtgyWsbTvWHFLm2wNY0JR',
64 | 'grant_type': 'refresh_token',
65 | 'code': ticket
66 | },
67 | headers: {
68 | 'User-Agent': 'niantic'
69 | }
70 | };
71 |
72 | self.request.post(options, function (err, response, body) {
73 | var token;
74 |
75 | if(err) {
76 | return callback(err, null);
77 | }
78 |
79 | token = body.split('token=')[1];
80 | token = token.split('&')[0];
81 |
82 | var expiry = body.split('token=')[1].split('&expires=')[1];
83 |
84 | if (!token) {
85 | return callback(new Error('Login failed'), null);
86 | }
87 |
88 | self.DebugPrint('[i] Session token: ' + token);
89 | callback(null, [token, expiry]);
90 | });
91 |
92 | });
93 |
94 | });
95 | },
96 | GoogleAccount: function (user, pass, self, callback) {
97 | self.google.login(user, pass, android_id, function (err, data) {
98 | if (data) {
99 | self.google.oauth(user, data.masterToken, data.androidId, oauth_service, app, client_sig, function (err, data) {
100 | if (err) {
101 | return callback(err, null);
102 | }
103 | callback(null, [data.Auth, data.Expiry]);
104 | });
105 | }
106 | else {
107 | return callback(err, null);
108 | }
109 | });
110 | }
111 | };
112 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pokemon-go-node-api",
3 | "version": "1.2.5",
4 | "description": "Pokemon GO node.js module",
5 | "author": "Derek M.F. P",
6 | "license": "MIT",
7 | "main": "poke.io.js",
8 | "dependencies": {
9 | "events": "^1.1.1",
10 | "geocoder": "^0.2.2",
11 | "gpsoauthnode": "^0.0.5",
12 | "istanbul": "^0.4.4",
13 | "protobufjs": "^5.0.1",
14 | "request": "^2.73.0",
15 | "s2geometry-node": "^1.3.0",
16 | "tape": "^4.6.0",
17 | "long": "^3.2.0",
18 | "node-pogo-signature": "https://github.com/SpencerSharkey/node-pogo-signature.git"
19 | },
20 | "devDependencies": {},
21 | "scripts": {
22 | "test": "istanbul cover node_modules/tape/bin/tape tests/**/*.js"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/d-pollard/Pokemon-GO-node-api"
27 | },
28 | "keywords": [
29 | "pokemon",
30 | "go",
31 | "api",
32 | "node",
33 | "pokemon-go",
34 | "niantic"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/poke.io.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const request = require('request');
4 | const geocoder = require('geocoder');
5 | const events = require('events');
6 | const ProtoBuf = require('protobufjs');
7 | const GoogleOAuth = require('gpsoauthnode');
8 | const Long = require('long');
9 | const ByteBuffer = require('bytebuffer');
10 | const crypto = require('crypto');
11 | const pogoSignature = require('node-pogo-signature');
12 |
13 | const s2 = require('s2geometry-node');
14 | const Logins = require('./logins');
15 | const fs = require('fs');
16 | const pokemonlist = JSON.parse(fs.readFileSync(__dirname + '/pokemons.json', 'utf8'));
17 |
18 | let builder = ProtoBuf.loadProtoFile('pokemon.proto');
19 | if (builder === null) {
20 | builder = ProtoBuf.loadProtoFile(__dirname + '/pokemon.proto');
21 | }
22 |
23 | const pokemonProto = builder.build();
24 | const {RequestEnvelop, ResponseEnvelop} = pokemonProto;
25 | const Signature = pokemonProto.Signature;
26 |
27 | const EventEmitter = events.EventEmitter;
28 |
29 | const api_url = 'https://pgorelease.nianticlabs.com/plfe/rpc';
30 |
31 | function GetCoords(self) {
32 | let {latitude, longitude} = self.playerInfo;
33 | return [latitude, longitude];
34 | };
35 |
36 |
37 | function getNeighbors(lat, lng) {
38 | var origin = new s2.S2CellId(new s2.S2LatLng(lat, lng)).parent(15);
39 | var walk = [origin.id()];
40 | // 10 before and 10 after
41 | var next = origin.next();
42 | var prev = origin.prev();
43 | for (var i = 0; i < 10; i++) {
44 | // in range(10):
45 | walk.push(prev.id());
46 | walk.push(next.id());
47 | next = next.next();
48 | prev = prev.prev();
49 | }
50 | return walk;
51 | }
52 |
53 | function Pokeio() {
54 | var self = this;
55 | self.events = new EventEmitter();
56 | self.j = request.jar();
57 | self.request = request.defaults({jar: self.j});
58 |
59 | self.google = new GoogleOAuth();
60 |
61 | self.playerInfo = {
62 | accessToken: '',
63 | debug: true,
64 | latitude: 0,
65 | longitude: 0,
66 | altitude: 0,
67 | locationName: '',
68 | provider: '',
69 | apiEndpoint: '',
70 | tokenExpire: 0,
71 | initTime: 0
72 | };
73 |
74 | self.myStats = false;
75 |
76 | self.DebugPrint = function (str) {
77 | if (self.playerInfo.debug === true) {
78 | //self.events.emit('debug',str)
79 | console.log(str);
80 | }
81 | };
82 |
83 | self.pokemonlist = pokemonlist.pokemon;
84 |
85 |
86 | function api_req(api_endpoint, access_token, req, callback) {
87 | // Auth
88 | var authInfo = new RequestEnvelop.AuthInfo({
89 | provider: self.playerInfo.provider,
90 | token: new RequestEnvelop.AuthInfo.JWT(access_token, 59)
91 | });
92 |
93 |
94 | // console.log(req);
95 |
96 | var f_req = new RequestEnvelop({
97 | unknown1: 2,
98 | rpc_id: 1469378659230941192,
99 |
100 | requests: req,
101 |
102 | latitude: self.playerInfo.latitude,
103 | longitude: self.playerInfo.longitude,
104 | altitude: self.playerInfo.altitude,
105 |
106 | unknown12: 989
107 | });
108 |
109 | if (self.playerInfo.authTicket) {
110 | f_req.auth_ticket = self.playerInfo.authTicket;
111 |
112 | var lat = self.playerInfo.latitude, lng = self.playerInfo.longitude, alt = self.playerInfo.altitude;
113 | var authTicketEncoded = self.playerInfo.authTicket.encode().toBuffer();
114 |
115 | var signature = new Signature({
116 | location_hash1: pogoSignature.utils.hashLocation1(authTicketEncoded, lat, lng, alt).toNumber(),
117 | location_hash2: pogoSignature.utils.hashLocation2(lat, lng, alt).toNumber(),
118 | unk22: crypto.randomBytes(32),
119 | timestamp: new Date().getTime(),
120 | timestamp_since_start: (new Date().getTime() - self.playerInfo.initTime),
121 | });
122 |
123 | if (!Array.isArray(req)) {
124 | req = [req];
125 | }
126 |
127 | req.forEach(function(request) {
128 | var reqHash = pogoSignature.utils.hashRequest(authTicketEncoded, request.encode().toBuffer()).toString();
129 | var hash = require('long').fromString(reqHash, true, 10);
130 | signature.request_hash.push(hash);
131 | });
132 |
133 | var iv = crypto.randomBytes(32);
134 |
135 | pogoSignature.encrypt(signature.encode().toBuffer(), iv, function(err, signatureEnc) {
136 | f_req.unknown6 = new RequestEnvelop.Unknown6({
137 | unknown1: 6,
138 | unknown2: new RequestEnvelop.Unknown6.Unknown2({
139 | unknown1: signatureEnc
140 | })
141 | });
142 | compiledProtobuf(f_req);
143 | });
144 |
145 | } else {
146 | f_req.auth = authInfo;
147 | compiledProtobuf(f_req);
148 | }
149 |
150 | function compiledProtobuf(protobuf) {
151 | //console.log(JSON.stringify(protobuf))
152 | protobuf = f_req.encode().toBuffer();
153 |
154 | var options = {
155 | url: api_endpoint,
156 | body: protobuf,
157 | encoding: null,
158 | headers: {
159 | 'User-Agent': 'Niantic App'
160 | }
161 | };
162 |
163 | self.request.post(options, function (err, response, body) {
164 | if (err) {
165 | return callback(new Error('Error'));
166 | }
167 |
168 | if (response === undefined || body === undefined) {
169 | console.error('[!] RPC Server offline');
170 | return callback(new Error('RPC Server offline'));
171 | }
172 |
173 | var f_ret;
174 | try {
175 | f_ret = ResponseEnvelop.decode(body);
176 | } catch (e) {
177 | if (e.decoded) {
178 | // Truncated
179 | console.warn(e);
180 | f_ret = e.decoded; // Decoded message with missing required fields
181 | }
182 | }
183 |
184 | if (f_ret) {
185 | if (f_ret.auth_ticket) {
186 | self.playerInfo.authTicket = f_ret.auth_ticket;
187 | }
188 | return callback(null, f_ret);
189 | } else {
190 | api_req(api_endpoint, access_token, req, callback);
191 | }
192 | });
193 | }
194 | }
195 |
196 | self.init = function (username, password, location, provider, callback) {
197 | if (provider !== 'ptc' && provider !== 'google') {
198 | return callback(new Error('Invalid provider'));
199 | }
200 |
201 | self.playerInfo.initTime = new Date().getTime();
202 |
203 | // set provider
204 | self.playerInfo.provider = provider;
205 | // Updating location
206 | self.SetLocation(location, function (err, loc) {
207 | if (err) {
208 | return callback(err);
209 | }
210 | // Getting access token
211 | self.GetAccessToken(username, password, function (err, token) {
212 | if (err) {
213 | return callback(err);
214 | }
215 | // Getting api endpoint
216 | self.GetApiEndpoint(function (err, api_endpoint) {
217 | if (err) {
218 | return callback(err);
219 | }
220 | callback(null);
221 | });
222 | });
223 | });
224 | };
225 |
226 | self.GetAccessToken = function (user, pass, callback) {
227 | self.DebugPrint('[i] Logging with user: ' + user);
228 | if (self.playerInfo.provider === 'ptc') {
229 | Logins.PokemonClub(user, pass, self, function (err, token) {
230 | if (err) {
231 | return callback(err);
232 | }
233 |
234 | self.playerInfo.accessToken = token;
235 | self.DebugPrint('[i] Received PTC access token!');
236 | callback(null, token);
237 | });
238 | } else {
239 | Logins.GoogleAccount(user, pass, self, function (err, token) {
240 | if (err) {
241 | return callback(err);
242 | }
243 |
244 | self.playerInfo.accessToken = token;
245 | self.DebugPrint('[i] Received Google access token!');
246 | callback(null, token);
247 | });
248 | }
249 | };
250 |
251 | self.GetAccessToken = function (user, pass, callback) {
252 | self.DebugPrint('[i] Logging with user: ' + user);
253 | if (self.playerInfo.provider === 'ptc') {
254 | Logins.PokemonClub(user, pass, self, function (err, token) {
255 | if (err) {
256 | return callback(err);
257 | }
258 |
259 | self.playerInfo.accessToken = token[0];
260 | self.playerInfo.tokenExpire = token[1];
261 | self.DebugPrint('[i] Received PTC access token! {Expires: ' + token[1] + '}');
262 | callback(null, token[0]);
263 | });
264 | } else {
265 | Logins.GoogleAccount(user, pass, self, function (err, token) {
266 | if (err) {
267 | return callback(err);
268 | }
269 |
270 | self.playerInfo.accessToken = token[0];
271 | self.playerInfo.tokenExpire = token[1];
272 | self.DebugPrint('[i] Received Google access token! {Expires: ' + token[1] + '}');
273 | callback(null, token[0]);
274 | });
275 | }
276 | };
277 |
278 |
279 |
280 | self.GetApiEndpoint = function (callback) {
281 | var req = [new RequestEnvelop.Requests(2), new RequestEnvelop.Requests(126), new RequestEnvelop.Requests(4), new RequestEnvelop.Requests(129), new RequestEnvelop.Requests(5)];
282 |
283 | api_req(api_url, self.playerInfo.accessToken, req, function (err, f_ret) {
284 | if (err) {
285 | return callback(err);
286 | }
287 | var api_endpoint = 'https://' + f_ret.api_url + '/rpc';
288 | self.playerInfo.apiEndpoint = api_endpoint;
289 | self.DebugPrint('[i] Received API Endpoint: ' + api_endpoint);
290 | return callback(null, api_endpoint);
291 | });
292 | };
293 |
294 | self.GetInventory = function(callback) {
295 | var req = new RequestEnvelop.Requests(4);
296 |
297 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req, function(err, f_ret){
298 | if(err){
299 | return callback(err);
300 | }
301 | var inventory = ResponseEnvelop.GetInventoryResponse.decode(f_ret.payload[0]);
302 | return callback(null, inventory);
303 | });
304 | };
305 |
306 | self.GetProfile = function (callback) {
307 | var req = new RequestEnvelop.Requests(2);
308 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req, function (err, f_ret) {
309 | if (err) {
310 | return callback(err);
311 | }
312 |
313 | var profile = ResponseEnvelop.ProfilePayload.decode(f_ret.payload[0]).profile
314 |
315 | if (profile.username) {
316 | self.DebugPrint('[i] Logged in!');
317 | }
318 | callback(null, profile);
319 | });
320 | };
321 |
322 | self.GetStats = function(callback) {
323 | self.GetInventory(function(a,b) {
324 | if(a === null) {
325 | var inventory = b.inventory_delta.inventory_items;
326 | for (var i = inventory.length - 1; i >= 0; i--) {
327 | var x = inventory[i];
328 | var stats = x.inventory_item_data.player_stats;
329 | if(stats !== null) {
330 | // console.log(stats);
331 | self.myStats = stats;
332 | callback(null, stats);
333 | return;
334 | } else {
335 | continue;
336 | }
337 | }
338 | } else {
339 | callback(a, null);
340 | }
341 | });
342 | };
343 |
344 | // IN DEVELPOMENT, YES WE KNOW IS NOT WORKING ATM
345 | self.Heartbeat = function (callback) {
346 | let {apiEndpoint, accessToken} = self.playerInfo;
347 |
348 |
349 | var nullbytes = new Array(21);
350 | nullbytes.fill(0);
351 |
352 | self.playerInfo.initTime = new Date().getTime();
353 |
354 | // Generating walk data using s2 geometry
355 | var walk = getNeighbors(self.playerInfo.latitude, self.playerInfo.longitude).sort(function (a, b) {
356 | return a > b;
357 | });
358 |
359 | // Creating MessageQuad for Requests type=106
360 | var walkData = new RequestEnvelop.MessageQuad({
361 | 'f1': walk,
362 | 'f2': nullbytes,
363 | 'lat': self.playerInfo.latitude,
364 | 'long': self.playerInfo.longitude
365 | });
366 |
367 | var req = [new RequestEnvelop.Requests(106, walkData.encode().toBuffer()), new RequestEnvelop.Requests(126), new RequestEnvelop.Requests(4, new RequestEnvelop.Unknown3(Date.now().toString()).encode().toBuffer()), new RequestEnvelop.Requests(129), new RequestEnvelop.Requests(5, new RequestEnvelop.Unknown3('54b359c97e46900f87211ef6e6dd0b7f2a3ea1f5').encode().toBuffer())];
368 |
369 | api_req(apiEndpoint, accessToken, req, function (err, f_ret) {
370 | if (err) {
371 | return callback(err);
372 | } else if (!f_ret || !f_ret.payload || !f_ret.payload[0]) {
373 | return callback('No result');
374 | }
375 |
376 | var heartbeat = ResponseEnvelop.HeartbeatPayload.decode(f_ret.payload[0]);
377 | callback(null, heartbeat);
378 | });
379 | };
380 |
381 | self.GetLocation = function (callback) {
382 | geocoder.reverseGeocode(...GetCoords(self), function (err, data) {
383 | if (data.status === 'ZERO_RESULTS') {
384 | return callback(new Error('location not found'));
385 | }
386 |
387 | callback(null, data.results[0].formatted_address);
388 | });
389 | };
390 |
391 | self.CatchPokemon = function (mapPokemon, pokeball, callback) {
392 | console.log('Attempting to catch now...');
393 | let {apiEndpoint, accessToken} = self.playerInfo;
394 | var catchPokemon = new RequestEnvelop.CatchPokemonMessage({
395 | 'encounter_id': mapPokemon.EncounterId,
396 | 'pokeball': pokeball,
397 | 'normalized_reticle_size': 1.950,
398 | 'spawnpoint_id': mapPokemon.SpawnPointId,
399 | 'hit_pokemon': true,
400 | 'spin_modifier': 1,
401 | 'normalized_hit_position': 1
402 | });
403 |
404 | // console.log(catchPokemon);
405 |
406 | var req = new RequestEnvelop.Requests(103, catchPokemon.encode().toBuffer());
407 |
408 | api_req(apiEndpoint, accessToken, req, function (err, f_ret) {
409 | if (err) {
410 | return callback(err);
411 | }
412 | else if (!f_ret || !f_ret.payload || !f_ret.payload[0]) {
413 | return callback('No result');
414 | }
415 |
416 | var catchPokemonResponse = ResponseEnvelop.CatchPokemonResponse.decode(f_ret.payload[0]);
417 | callback(null, catchPokemonResponse)
418 | });
419 |
420 | };
421 |
422 | self.EncounterPokemon = function (catchablePokemon, callback) {
423 | // console.log(catchablePokemon);
424 | let {apiEndpoint, accessToken, latitude, longitude} = self.playerInfo;
425 |
426 | var encounterPokemon = new RequestEnvelop.EncounterMessage({
427 | 'encounter_id': catchablePokemon.EncounterId,
428 | 'spawnpoint_id': catchablePokemon.SpawnPointId,
429 | 'player_latitude': latitude,
430 | 'player_longitude': longitude
431 | });
432 |
433 | // console.log(encounterPokemon);
434 |
435 | var req = new RequestEnvelop.Requests(102, encounterPokemon.encode().toBuffer());
436 |
437 | api_req(apiEndpoint, accessToken, req, function (err, f_ret) {
438 | if (err) {
439 | return callback(err);
440 | }
441 | else if (!f_ret || !f_ret.payload || !f_ret.payload[0]) {
442 | return callback('No result');
443 | }
444 |
445 | var catchPokemonResponse = ResponseEnvelop.EncounterResponse.decode(f_ret.payload[0]);
446 |
447 | callback(null, catchPokemonResponse);
448 | });
449 |
450 | };
451 |
452 | self.GetLocationCoords = function () {
453 | let {latitude, longitude, altitude} = self.playerInfo;
454 | return {latitude, longitude, altitude};
455 | };
456 |
457 | self.SetLocation = function (location, callback) {
458 | if (location.type !== 'name' && location.type !== 'coords') {
459 | return callback(new Error('Invalid location type'));
460 | }
461 |
462 | if (location.type === 'name') {
463 | if (!location.name) {
464 | return callback(new Error('You should add a location name'));
465 | }
466 | var locationName = location.name;
467 | geocoder.geocode(locationName, function (err, data) {
468 | if (err || data.status === 'ZERO_RESULTS') {
469 | return callback(new Error('location not found'));
470 | }
471 |
472 | let {lat, lng} = data.results[0].geometry.location;
473 |
474 | self.playerInfo.latitude = lat;
475 | self.playerInfo.longitude = lng;
476 | self.playerInfo.locationName = locationName;
477 |
478 | callback(null, self.GetLocationCoords());
479 | });
480 | } else if (location.type === 'coords') {
481 | if (!location.coords) {
482 | return callback(new Error('Coords object missing'));
483 | }
484 |
485 | self.playerInfo.latitude = location.coords.latitude || self.playerInfo.latitude;
486 | self.playerInfo.longitude = location.coords.longitude || self.playerInfo.longitude;
487 | self.playerInfo.altitude = location.coords.altitude || self.playerInfo.altitude;
488 |
489 | geocoder.reverseGeocode(...GetCoords(self), function (err, data) {
490 | if (data.status !== 'ZERO_RESULTS' && data.results && data.results[0]) {
491 | self.playerInfo.locationName = data.results[0].formatted_address;
492 | }
493 |
494 | callback(null, self.GetLocationCoords());
495 | });
496 | }
497 | };
498 |
499 | self.changePosition = function () {
500 | self.playerInfo.longitude = self.playerInfo.longitude + 0.000055;
501 | self.playerInfo.latitude = self.playerInfo.latitude + 0.000055;
502 | return true;
503 | };
504 |
505 | self.hatchEggs = function(cb) {
506 | self.changePosition();
507 | self.Heartbeat(cb);
508 | };
509 |
510 | self.GetFort = function(fortid, fortlat, fortlong, callback) {
511 | var FortMessage = new RequestEnvelop.FortSearchMessage({
512 | 'fort_id': fortid,
513 | 'player_latitude': fortlat,
514 | 'player_longitude': fortlong,
515 | 'fort_latitude': fortlat,
516 | 'fort_longitude': fortlong
517 | });
518 |
519 | // console.log(FortMessage);
520 |
521 | var req = new RequestEnvelop.Requests(101, FortMessage.encode().toBuffer());
522 |
523 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req, function (err, f_ret) {
524 | if (err) {
525 | return callback(err);
526 | } else if (!f_ret || !f_ret.payload || !f_ret.payload[0]) {
527 | return callback('No result');
528 | }
529 |
530 | var FortSearchResponse = ResponseEnvelop.FortSearchResponse.decode(f_ret.payload[0]);
531 | callback(null, FortSearchResponse);
532 | });
533 | };
534 |
535 | self.warpSpeed = function(lat,long) {
536 | self.playerInfo.latitude = lat;
537 | self.playerInfo.longitude = long;
538 | return true;
539 | };
540 | }
541 |
542 | module.exports = new Pokeio();
543 | module.exports.Pokeio = Pokeio;
544 | module.exports.Pokego = require('./pokego.js');
545 |
--------------------------------------------------------------------------------
/pokego.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const request = require('request');
4 | const geocoder = require('geocoder');
5 | const events = require('events');
6 | const ProtoBuf = require('protobufjs');
7 | const GoogleOAuth = require('gpsoauthnode');
8 | const Long = require('long');
9 | const ByteBuffer = require('bytebuffer');
10 |
11 | const s2 = require('s2geometry-node');
12 | const Logins = require('./auth');
13 | const fs = require('fs');
14 | const pokemonlist = JSON.parse(fs.readFileSync(__dirname + '/pokemons.json', 'utf8'));
15 |
16 | let builder = ProtoBuf.loadProtoFile('pokemon.proto');
17 | if (builder === null) {
18 | builder = ProtoBuf.loadProtoFile(__dirname + '/pokemon.proto');
19 | }
20 |
21 | const pokemonProto = builder.build();
22 | const {RequestEnvelop, ResponseEnvelop} = pokemonProto;
23 |
24 | const EventEmitter = events.EventEmitter;
25 |
26 | const api_url = 'https://pgorelease.nianticlabs.com/plfe/rpc';
27 |
28 | function GetCoords(self) {
29 | let {latitude, longitude} = self.playerInfo;
30 | return [latitude, longitude];
31 | };
32 |
33 |
34 | function getNeighbors(lat, lng) {
35 | var origin = new s2.S2CellId(new s2.S2LatLng(lat, lng)).parent(15);
36 | var walk = [origin.id()];
37 | // 10 before and 10 after
38 | var next = origin.next();
39 | var prev = origin.prev();
40 | for (var i = 0; i < 10; i++) {
41 | // in range(10):
42 | walk.push(prev.id());
43 | walk.push(next.id());
44 | next = next.next();
45 | prev = prev.prev();
46 | }
47 | return walk;
48 | }
49 |
50 | function Pokego() {
51 | var self = this;
52 | self.events = new EventEmitter();
53 | self.j = request.jar();
54 | self.request = request.defaults({jar: self.j});
55 |
56 | self.google = new GoogleOAuth();
57 |
58 | self.playerInfo = {
59 | accessToken: '',
60 | debug: true,
61 | latitude: 0,
62 | longitude: 0,
63 | altitude: 0,
64 | locationName: '',
65 | provider: '',
66 | apiEndpoint: '',
67 | tokenExpire: 0
68 | };
69 |
70 | self.myStats = false;
71 |
72 | self.DebugPrint = function (str) {
73 | if (self.playerInfo.debug === true) {
74 | //self.events.emit('debug',str)
75 | console.log(str);
76 | }
77 | };
78 |
79 | self.pokemonlist = pokemonlist.pokemon;
80 |
81 | function api_req(api_endpoint, access_token, req) {
82 | // Auth
83 | var auth = new RequestEnvelop.AuthInfo({
84 | provider: self.playerInfo.provider,
85 | token: new RequestEnvelop.AuthInfo.JWT(access_token, 59)
86 | });
87 |
88 | var f_req = new RequestEnvelop({
89 | unknown1: 2,
90 | rpc_id: 1469378659230941192,
91 |
92 | requests: req,
93 |
94 | latitude: self.playerInfo.latitude,
95 | longitude: self.playerInfo.longitude,
96 | altitude: self.playerInfo.altitude,
97 |
98 | auth: auth,
99 | unknown12: 989
100 | });
101 |
102 | var protobuf = f_req.encode().toBuffer();
103 |
104 | var options = {
105 | url: api_endpoint,
106 | body: protobuf,
107 | encoding: null,
108 | headers: {
109 | 'User-Agent': 'Niantic App'
110 | }
111 | };
112 |
113 | return new Promise(function(resolve, reject) {
114 |
115 | self.request.post(options, function (err, response, body) {
116 | if (response === undefined || body === undefined) {
117 | console.error('[!] RPC Server offline');
118 | return reject('Error');
119 | }
120 |
121 | try {
122 | var f_ret = ResponseEnvelop.decode(body);
123 | } catch (e) {
124 | if (e.decoded) { // Truncated
125 | console.warn(e);
126 | f_ret = e.decoded; // Decoded message with missing required fields
127 | resolve(f_ret);
128 | }
129 | }
130 | if (f_ret) {
131 | return resolve(f_ret);
132 | }
133 | else {
134 | api_req(api_endpoint, access_token, req)
135 | }
136 | });
137 | });
138 | }
139 |
140 |
141 | self.init = function(username, password, location, provider) {
142 | console.log('..:: Initializing the API ::..');
143 | return new Promise(function(resolve, reject) {
144 | if(provider !== 'ptc' && provider !== 'google') {
145 | return reject('Provider is not supported');
146 | } else {
147 | self.playerInfo.provider = provider;
148 | self.SetLocation(location).then((val) => {
149 | self.GetAccessToken(username, password).then((val) => {
150 | self.GetApiEndpoint().then((val) => {
151 | return resolve(val);
152 | })
153 | .catch((err) => {
154 | console.log(err);
155 | });
156 | })
157 | .catch((err) => {
158 | console.log(err);
159 | });
160 | })
161 | .catch((err) => {
162 | console.log(err);
163 | });
164 | }
165 | });
166 | };
167 |
168 | self.GetAccessToken = function (user, pass, callback) {
169 | return new Promise(function(resolve, reject) {
170 | self.DebugPrint('[i] Logging with user: ' + user);
171 | if(self.playerInfo.provider === 'ptc') {
172 | Logins.PokemonClub(user, pass, self).then((token) => {
173 | self.playerInfo.accessToken = token[0];
174 | self.playerInfo.tokenExpire = token[1];
175 | self.DebugPrint('[i] Received PTC access token! { Expires: ' + token[1] + ' }');
176 | return resolve(token[0]);
177 | }).catch((err) => {
178 | return reject('[x] There was an error logging in. Please try again.')
179 | });
180 | } else {
181 | Logins.GoogleAccount(user, pass, self).then((token) => {
182 | self.playerInfo.accessToken = token[0];
183 | self.playerInfo.tokenExpire = token[1];
184 | self.DebugPrint('[i] Received Google access token! {Expires: ' + token[1] + '}');
185 | return resolve(token[0]);
186 | });
187 | }
188 | });
189 | };
190 |
191 |
192 | self.GetApiEndpoint = function () {
193 | return new Promise(function(resolve, reject) {
194 | var req = [
195 | new RequestEnvelop.Requests(2),
196 | new RequestEnvelop.Requests(126),
197 | new RequestEnvelop.Requests(4),
198 | new RequestEnvelop.Requests(129),
199 | new RequestEnvelop.Requests(5)
200 | ];
201 | api_req(api_url, self.playerInfo.accessToken, req).then((f_ret) => {
202 | var apiEndpoint = `https://${f_ret.api_url}/rpc`;
203 | if(apiEndpoint === 'https://null/rpc') {
204 | return reject('[x] There seams to be an issue. Please try again.')
205 | }
206 | self.playerInfo.apiEndpoint = apiEndpoint;
207 | self.DebugPrint('[i] Received API Endpoint: ' + apiEndpoint);
208 | return resolve(apiEndpoint);
209 | });
210 | });
211 | };
212 |
213 | self.GetInventory = function() {
214 | return new Promise(function(resolve, reject) {
215 | var req = new RequestEnvelop.Requests(4);
216 |
217 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req).then((f_ret) => {
218 | var inventory = ResponseEnvelop.GetInventoryResponse.decode(f_ret.payload[0]);
219 | return resolve(inventory);
220 | }).catch((val) => {
221 | console.log(val);
222 | });
223 | });
224 | };
225 |
226 | self.displayInventory = function(data) {
227 | //console.log(data);
228 | var inventory = data.inventory_delta.inventory_items;
229 | // console.log(inventory.length);
230 | for (var i = inventory.length - 1; i >= 0; i--) {
231 | var x = inventory[i];
232 | var pokemon = x.inventory_item_data.pokemon;
233 | var item = x.inventory_item_data.item;
234 | var candy = x.inventory_item_data.pokemon_family;
235 | var stats = x.inventory_item_data.player_stats;
236 | if(pokemon !== null && pokemon.pokemon_id !== null) {
237 | // item is a pokemon
238 | var pkmn = self.pokemonlist[parseInt(pokemon.pokemon_id)-1];
239 | console.log(pkmn.name + ' -> ' + pokemon.cp + 'cp ');
240 | } else if(item !== null && item.item !== null) {
241 | // item is an actual item
242 | console.log(self.whatItem(item.item) + ' -> ' + (item.count || 0) + ' count');
243 | } else if(candy !== null && candy.family_id !== null){
244 | // item is a candy
245 | console.log(self.whatFamily(candy.family_id) + ' -> ' + (candy.candy || 0) + ' count');
246 | } else if(pokemon !== null && pokemon.is_egg === true) {
247 | // item *might be* an egg
248 | console.log('An egg');
249 | } else if(stats !== null) {
250 | console.log(stats);
251 | } else {
252 | // console.log(x);
253 | }
254 | }
255 | };
256 |
257 | self.getStats = function() {
258 | return new Promise(function(resolve, reject) {
259 | self.GetInventory().then((data) => {
260 | var inventory = data.inventory_delta.inventory_items;
261 | for (var i = inventory.length - 1; i >= 0; i--) {
262 | var x = inventory[i];
263 | var stats = x.inventory_item_data.player_stats;
264 | if(stats !== null) {
265 | // console.log(stats);
266 | self.myStats = stats;
267 | return resolve(stats);
268 | } else {
269 | continue;
270 | }
271 | }
272 | });
273 | });
274 | };
275 |
276 | self.GetProfile = function () {
277 | return new Promise(function(resolve, reject) {
278 | var req = new RequestEnvelop.Requests(2);
279 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req).then((f_ret) => {
280 | var profile = ResponseEnvelop.ProfilePayload.decode(f_ret.payload[0]).profile
281 | if (profile.username) {
282 | self.DebugPrint('[i] Player Profile');
283 | }
284 | return resolve(profile);
285 | }).catch((err) => {
286 | console.log(err);
287 | });
288 | });
289 | };
290 |
291 | // IN DEVELPOMENT, YES WE KNOW IS NOT WORKING ATM
292 | self.Heartbeat = function () {
293 | let { apiEndpoint, accessToken } = self.playerInfo;
294 |
295 |
296 | var nullbytes = new Array(21);
297 | nullbytes.fill(0);
298 |
299 | // Generating walk data using s2 geometry
300 | var walk = getNeighbors(self.playerInfo.latitude, self.playerInfo.longitude).sort(function (a, b) {
301 | return a > b;
302 | });
303 |
304 | // Creating MessageQuad for Requests type=106
305 | var walkData = new RequestEnvelop.MessageQuad({
306 | 'f1': walk,
307 | 'f2': nullbytes,
308 | 'lat': self.playerInfo.latitude,
309 | 'long': self.playerInfo.longitude
310 | });
311 |
312 | var req = [new RequestEnvelop.Requests(106, walkData.encode().toBuffer()), new RequestEnvelop.Requests(126), new RequestEnvelop.Requests(4, new RequestEnvelop.Unknown3(Date.now().toString()).encode().toBuffer()), new RequestEnvelop.Requests(129), new RequestEnvelop.Requests(5, new RequestEnvelop.Unknown3('05daf51635c82611d1aac95c0b051d3ec088a930').encode().toBuffer())];
313 | return new Promise(function(resolve, reject) {
314 | api_req(apiEndpoint, accessToken, req).then((data) => {
315 | if (!data || !data.payload || !data.payload[0]) {
316 | return reject('No data. API Failure.');
317 | }
318 | var heartbeat = ResponseEnvelop.HeartbeatPayload.decode(data.payload[0]);
319 | return resolve(heartbeat);
320 | }).catch((err) => {
321 | console.log(err);
322 | });
323 | }).catch((err) => {
324 | console.log(err);
325 | });
326 | };
327 |
328 | self.GetLocation = function () {
329 | geocoder.reverseGeocode(...GetCoords(self), function (err, data) {
330 | if (data.status === 'ZERO_RESULTS') {
331 | return callback(new Error('location not found'));
332 | }
333 | callback(null, data.results[0].formatted_address);
334 | });
335 | };
336 |
337 | self.fireAndForgetCatch = function(catchablePokemon, name, cnt, ball) {
338 | if(ball === 'POKE_BALL') { ball = 1; } else if(ball === 'GREAT_BALL') { ball = 2; } else { ball = 3; }
339 | return new Promise(function(resolve, reject) {
340 | self.EncounterPokemon(catchablePokemon).then((data) => {
341 | self.CatchPokemon(data.WildPokemon, ball).then((final) => {
342 | var status = ['Unexpected error', 'Successful catch', 'Catch Escape', 'Catch Flee', 'Missed Catch'];
343 | if(final.Status == null) {
344 | console.log('[x] Error: You have no more of that ball left to use!');
345 | } else {
346 | console.log('[s] Catch status for ' + name + ': ' + status[parseInt(final.Status)]);
347 | }
348 | return resolve(cnt);
349 | }).catch((err) => {
350 | console.log(err);
351 | });
352 | }).catch((err) => {
353 | console.log(err);
354 | });
355 | });
356 | };
357 |
358 | self.CatchPokemon = function (mapPokemon, pokeball) {
359 | console.log('Attempting to catch now...');
360 | // console.log(mapPokemon);
361 | let {apiEndpoint, accessToken} = self.playerInfo;
362 | var catchPokemon = new RequestEnvelop.CatchPokemonMessage({
363 | 'encounter_id': mapPokemon.EncounterId,
364 | 'pokeball': pokeball,
365 | 'normalized_reticle_size': 1.950,
366 | 'spawnpoint_id': mapPokemon.SpawnPointId,
367 | 'hit_pokemon': true,
368 | 'spin_modifier': 1,
369 | 'normalized_hit_position': 1
370 | });
371 |
372 | var req = new RequestEnvelop.Requests(103, catchPokemon.encode().toBuffer());
373 | return new Promise(function(resolve, reject) {
374 | api_req(apiEndpoint, accessToken, req).then((data) => {
375 | if (!data || !data.payload || !data.payload[0]) {
376 | return reject(data);
377 | }
378 | var catchPokemonResponse = ResponseEnvelop.CatchPokemonResponse.decode(data.payload[0]);
379 | return resolve(catchPokemonResponse);
380 | });
381 | });
382 | };
383 |
384 | self.EncounterPokemon = function (catchablePokemon) {
385 | // console.log(catchablePokemon);
386 | let {apiEndpoint, accessToken, latitude, longitude} = self.playerInfo;
387 |
388 | var encounterPokemon = new RequestEnvelop.EncounterMessage({
389 | 'encounter_id': catchablePokemon.EncounterId,
390 | 'spawnpoint_id': catchablePokemon.SpawnPointId,
391 | 'player_latitude': latitude,
392 | 'player_longitude': longitude
393 | });
394 |
395 | // console.log(encounterPokemon);
396 |
397 | var req = new RequestEnvelop.Requests(102, encounterPokemon.encode().toBuffer());
398 |
399 | return new Promise(function(resolve, reject) {
400 |
401 | api_req(apiEndpoint, accessToken, req).then((data) => {
402 | if (!data || !data.payload || !data.payload[0]) {
403 | return reject(data);
404 | }
405 | var catchPokemonResponse = ResponseEnvelop.EncounterResponse.decode(data.payload[0]);
406 | // console.log(catchPokemonResponse);
407 | return resolve(catchPokemonResponse);
408 | });
409 | });
410 | };
411 |
412 | self.GetLocationCoords = function () {
413 | let {latitude, longitude, altitude} = self.playerInfo;
414 | return {latitude, longitude, altitude};
415 | };
416 |
417 | self.setCoords = function(lt,ln) {
418 | self.playerInfo.latitude = lt;
419 | self.playerInfo.longitude = ln;
420 | return true;
421 | };
422 |
423 | self.SetLocation = function (location) {
424 | return new Promise(function(resolve, reject) {
425 | if (location.type !== 'name' && location.type !== 'coords') {
426 | return reject('You need to add a location name OR coordinates. API Failure.');
427 | } else {
428 | if (location.type === 'name') {
429 | if(location.name === 'name' || location.name === '') {
430 | return reject('You need to add a location name OR coordinates. API Failure.');
431 | } else {
432 | let locationName = location.name;
433 | geocoder.geocode(locationName, function(err, data) {
434 | if(err || data.status === 'ZERO_RESULTS') {
435 | return reject('Location not found. API Failure.');
436 | } else {
437 | let {lat, lng} = data.results[0].geometry.location;
438 | self.setCoords(lat, lng);
439 | self.playerInfo.locationName = locationName;
440 |
441 | return resolve(self.GetLocationCoords());
442 | }
443 | });
444 | }
445 | } else if(location.type === 'coords') {
446 | if(!location.coords) {
447 | return reject('Coordinates are missing. API Failure.');
448 | } else {
449 | self.playerInfo.latitude = location.coords.latitude || self.playerInfo.latitude;
450 | self.playerInfo.longitude = location.coords.longitude || self.playerInfo.longitude;
451 | self.playerInfo.altitude = location.coords.altitude || self.playerInfo.altitude;
452 |
453 | geocoder.reverseGeocode(...GetCoords(self), function(err, data) {
454 | if (data.status !== 'ZERO_RESULTS' && data.results && data.results[0]) {
455 | self.playerInfo.locationName = data.results[0].formatted_address;
456 | }
457 | return resolve(self.GetLocationCoords());
458 | });
459 | }
460 |
461 | } else {
462 | return reject('No data passed. API failure.')
463 | }
464 | }
465 | });
466 | };
467 |
468 | self.changePosition = function () {
469 | self.playerInfo.longitude = self.playerInfo.longitude + 0.000055;
470 | self.playerInfo.latitude = self.playerInfo.latitude + 0.000055;
471 | return true;
472 | };
473 |
474 | self.hatchEggs = function(cb) {
475 | self.changePosition();
476 | self.Heartbeat(cb);
477 | };
478 |
479 | self.GetFort = function(fortid, fortlat, fortlong, callback) {
480 | var FortMessage = new RequestEnvelop.FortSearchMessage({
481 | 'fort_id': fortid,
482 | 'player_latitude': fortlat,
483 | 'player_longitude': fortlong,
484 | 'fort_latitude': fortlat,
485 | 'fort_longitude': fortlong
486 | });
487 |
488 | var req = new RequestEnvelop.Requests(101, FortMessage.encode().toBuffer());
489 | return new Promise(function(resolve, reject) {
490 | api_req(self.playerInfo.apiEndpoint, self.playerInfo.accessToken, req).then((err, f_ret) => {
491 | if (err) {
492 | return reject(err);
493 | } else if (!f_ret || !f_ret.payload || !f_ret.payload[0]) {
494 | return reject('No result');
495 | }
496 |
497 | var FortSearchResponse = ResponseEnvelop.FortSearchResponse.decode(f_ret.payload[0]);
498 | return resolve(FortSearchResponse);
499 | });
500 | });
501 | };
502 |
503 | self.warpSpeed = function(lat,long) {
504 | self.playerInfo.latitude = lat;
505 | self.playerInfo.longitude = long;
506 | return true;
507 | };
508 |
509 | self.formatPlayercard = function(profile) {
510 | let team = ['Nuetral','Mystic','Valor','Instinct'];
511 | console.log('[o] -> Player: ' + profile.username);
512 | console.log('[o] -> Team: ' + team[profile.team]);
513 | console.log('[o] -> Created: ' + self.timeConverter(parseInt(profile.creation_time)));
514 | console.log('[o] -> Poke Storage: ' + profile.poke_storage);
515 | console.log('[o] -> Item Storage: ' + profile.item_storage);
516 | console.log('[o] -> Poke Coin: ' + profile.currency[0].amount);
517 | console.log('[o] -> Star Dust: ' + profile.currency[1].amount);
518 | console.log('[o] -> location lat:' + self.playerInfo.latitude + ' lng: ' + self.playerInfo.longitude);
519 | return true;
520 | };
521 |
522 |
523 |
524 | self.timeConverter = function(x){
525 | var a = new Date(x);
526 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
527 | var year = a.getFullYear();
528 | var month = months[a.getMonth()];
529 | var date = a.getDate();
530 | var hour = a.getHours();
531 | var min = a.getMinutes();
532 | var sec = a.getSeconds();
533 | var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ;
534 | return time;
535 | }
536 |
537 | self.whatItem = function(x) {
538 | var itemsArr = { 1: 'ITEM_POKE_BALL', 2: 'ITEM_GREAT_BALL', 3: 'ITEM_ULTRA_BALL', 4: 'ITEM_MASTER_BALL', 101: 'ITEM_POTION', 102: 'ITEM_SUPER_POTION', 103: 'ITEM_HYPER_POTION', 104: 'ITEM_MAX_POTION', 201: 'ITEM_REVIVE', 301: 'ITEM_LUCKY_EGG', 401: 'ITEM_INCENSE_ORDINARY', 402: 'ITEM_INCENSE_SPICY', 403: 'ITEM_INCENSE_COOL', 404: 'ITEM_INCENSE_FLORAL', 501: 'ITEM_TROY_DISK', 602: 'ITEM_X_ATTACK', 603: 'ITEM_X_DEFENSE', 604: 'ITEM_X_MIRACLE', 701: 'ITEM_RAZZ_BERRY', 702: 'ITEM_BLUK_BERRY', 703: 'ITEM_NANAB_BERRY', 704: 'ITEM_WEPAR_BERRY', 705: 'ITEM_PINAP_BERRY', 801: 'ITEM_SPECIAL_CAMERA', 901: 'ITEM_INCUBATOR_BASIC_UNLIMITED', 902: 'ITEM_INCUBATOR_BASIC', 1001: 'ITEM_POKEMON_STORAGE_UPGRADE', 1002: 'ITEM_ITEM_STORAGE_UPGRADE'};
539 | return itemsArr[x];
540 | };
541 |
542 | self.whatFamily = function(x) {
543 | var candyClass = {0: 'FAMILY_UNSET', 1: 'FAMILY_BULBASAUR', 4: 'FAMILY_CHARMANDER', 7: 'FAMILY_SQUIRTLE', 10: 'FAMILY_CATERPIE', 13: 'FAMILY_WEEDLE', 16: 'FAMILY_PIDGEY', 19: 'FAMILY_RATTATA', 21: 'FAMILY_SPEAROW', 23: 'FAMILY_EKANS', 25: 'FAMILY_PIKACHU', 27: 'FAMILY_SANDSHREW', 29: 'FAMILY_NIDORAN_FEMALE', 32: 'FAMILY_NIDORAN_MALE', 35: 'FAMILY_CLEFAIRY', 37: 'FAMILY_VULPIX', 39: 'FAMILY_JIGGLYPUFF', 41: 'FAMILY_ZUBAT', 43: 'FAMILY_ODDISH', 46: 'FAMILY_PARAS', 48: 'FAMILY_VENONAT', 50: 'FAMILY_DIGLETT', 52: 'FAMILY_MEOWTH', 54: 'FAMILY_PSYDUCK', 56: 'FAMILY_MANKEY', 58: 'FAMILY_GROWLITHE', 60: 'FAMILY_POLIWAG', 63: 'FAMILY_ABRA', 66: 'FAMILY_MACHOP', 69: 'FAMILY_BELLSPROUT', 72: 'FAMILY_TENTACOOL', 74: 'FAMILY_GEODUDE', 77: 'FAMILY_PONYTA', 79: 'FAMILY_SLOWPOKE', 81: 'FAMILY_MAGNEMITE', 83: 'FAMILY_FARFETCHD', 84: 'FAMILY_DODUO', 86: 'FAMILY_SEEL', 88: 'FAMILY_GRIMER', 90: 'FAMILY_SHELLDER', 92: 'FAMILY_GASTLY', 95: 'FAMILY_ONIX', 96: 'FAMILY_DROWZEE', 97: 'FAMILY_HYPNO', 98: 'FAMILY_KRABBY', 100: 'FAMILY_VOLTORB', 102: 'FAMILY_EXEGGCUTE', 104: 'FAMILY_CUBONE', 106: 'FAMILY_HITMONLEE', 107: 'FAMILY_HITMONCHAN', 108: 'FAMILY_LICKITUNG', 109: 'FAMILY_KOFFING', 110: 'FAMILY_DEREK', 111: 'FAMILY_RHYHORN', 113: 'FAMILY_CHANSEY', 114: 'FAMILY_TANGELA', 115: 'FAMILY_KANGASKHAN', 116: 'FAMILY_HORSEA', 118: 'FAMILY_GOLDEEN', 120: 'FAMILY_STARYU', 122: 'FAMILY_MR_MIME', 123: 'FAMILY_SCYTHER', 124: 'FAMILY_JYNX', 125: 'FAMILY_ELECTABUZZ', 126: 'FAMILY_MAGMAR', 127: 'FAMILY_PINSIR', 128: 'FAMILY_TAUROS', 129: 'FAMILY_MAGIKARP', 131: 'FAMILY_LAPRAS', 132: 'FAMILY_DITTO', 133: 'FAMILY_EEVEE', 137: 'FAMILY_PORYGON', 138: 'FAMILY_OMANYTE', 140: 'FAMILY_KABUTO', 142: 'FAMILY_AERODACTYL', 143: 'FAMILY_SNORLAX', 144: 'FAMILY_ARTICUNO', 145: 'FAMILY_ZAPDOS', 146: 'FAMILY_MOLTRES', 147: 'FAMILY_DRATINI', 150: 'FAMILY_MEWTWO', 151: 'FAMILY_MEW'};
544 | return candyClass[x];
545 | };
546 |
547 |
548 | };
549 |
550 | module.exports = new Pokego();
551 | module.exports.Pokego = Pokego;
552 |
--------------------------------------------------------------------------------
/pokemon.proto:
--------------------------------------------------------------------------------
1 | message RequestEnvelop {
2 | required int32 unknown1 = 1;
3 | optional int64 rpc_id = 3;
4 | repeated Requests requests = 4;
5 | optional Unknown6 unknown6 = 6;
6 | optional double latitude = 7;
7 | optional double longitude = 8;
8 | optional double altitude = 9;
9 | optional AuthInfo auth = 10;
10 | optional AuthTicket auth_ticket = 11;
11 | optional int64 unknown12 = 12;
12 |
13 | message Requests {
14 | required int32 type = 1;
15 | optional bytes message = 2;
16 | }
17 |
18 | message Unknown3 {
19 | required string unknown4 = 1;
20 | }
21 |
22 | message Unknown6 {
23 | required int32 unknown1 = 1;
24 | required Unknown2 unknown2 = 2;
25 |
26 | message Unknown2 {
27 | required bytes unknown1 = 1;
28 | }
29 |
30 | }
31 |
32 | message AuthTicket {
33 | optional bytes start = 1;
34 | optional uint64 expire_timestamp_ms = 2;
35 | optional bytes end = 3;
36 | }
37 |
38 | message AuthInfo {
39 | required string provider = 1;
40 | required JWT token = 2;
41 |
42 | message JWT {
43 | required string contents = 1;
44 | required int32 unknown13 = 2;
45 | }
46 | }
47 |
48 | message MessageQuad {
49 | repeated uint64 f1 = 1 [packed=true];
50 | repeated int64 f2 = 2 [packed=true];
51 | required double lat = 3;
52 | required double long = 4;
53 | }
54 |
55 | message CatchPokemonMessage {
56 | required fixed64 encounter_id = 1;
57 | required int32 pokeball = 2;
58 | required double normalized_reticle_size = 3;
59 | required string spawnpoint_id = 4;
60 | required bool hit_pokemon = 5;
61 | required double spin_modifier = 6;
62 | required double normalized_hit_position = 7;
63 | }
64 |
65 | message EvolvePokemonMessage {
66 | required fixed64 PokemonId = 1;
67 | }
68 |
69 | message TransferPokemonMessage {
70 | required fixed64 PokemonId = 1;
71 | }
72 |
73 | message LevelUpRewardsMessage {
74 | required int32 level = 1;
75 | }
76 |
77 | message UseItemEggIncubatorMessage {
78 | required string item_id = 1;
79 | required uint64 PokemonId = 2;
80 | }
81 |
82 | message GetHatchedEggsMessage {
83 | // nothin..
84 | }
85 | message UseItemXpBoostMessage {
86 | required int32 item_id = 1;
87 | }
88 |
89 | message EncounterMessage {
90 | repeated fixed64 encounter_id = 1;
91 | required string spawnpoint_id = 2;
92 | required double player_latitude = 3;
93 | required double player_longitude = 4;
94 | }
95 |
96 | message FortSearchMessage {
97 | required string fort_id = 1;
98 | required double player_latitude = 2;
99 | required double player_longitude = 3;
100 | required double fort_latitude = 4;
101 | required double fort_longitude = 5;
102 | }
103 |
104 | message FortDetailsRequest
105 | {
106 | required string fort_id = 1;
107 | required double fort_latitude = 2;
108 | required double fort_longitude = 3;
109 | }
110 |
111 | //rpc id : 137
112 | message RecycleInventoryItemMessage {
113 | required int32 item_id = 1;
114 | required int32 count = 2;
115 | }
116 |
117 | message ReleasePokemonMessage {
118 | optional fixed64 pokemon_id = 1;
119 | repeated fixed64 pokemon_ids = 2;
120 | }
121 | }
122 |
123 | message ResponseEnvelop {
124 | optional int32 unknown1 = 1;
125 | optional int64 unknown2 = 2;
126 | optional string api_url = 3;
127 | optional Unknown6 unknown6 = 6;
128 | optional AuthTicket auth_ticket = 7;
129 | repeated bytes payload = 100;
130 |
131 | message Unknown6 {
132 | required int32 unknown1 = 1;
133 | required Unknown2 unknown2 = 2;
134 |
135 | message Unknown2 {
136 | optional uint64 unknown1 = 1;
137 | repeated bytes storeitems = 2;
138 | repeated bytes currencies = 3;
139 | optional string unknown4 = 4;
140 | }
141 |
142 | }
143 |
144 | message AuthTicket {
145 | optional bytes start = 1;
146 | optional uint64 expire_timestamp_ms = 2;
147 | optional bytes end = 3;
148 | }
149 |
150 | message HeartbeatPayload {
151 | repeated ClientMapCell cells = 1;
152 | }
153 |
154 | message ClientMapCell {
155 | required uint64 S2CellId = 1;
156 | required int64 AsOfTimeMs = 2;
157 | repeated PokemonFortProto Fort = 3;
158 | repeated ClientSpawnPointProto SpawnPoint = 4;
159 | repeated WildPokemonProto WildPokemon = 5;
160 | //unknown DeletedObject = 6;
161 | optional bool IsTruncatedList = 7;
162 | repeated PokemonSummaryFortProto FortSummary = 8;
163 | repeated ClientSpawnPointProto DecimatedSpawnPoint = 9;
164 | repeated MapPokemonProto MapPokemon = 10;
165 | repeated NearbyPokemonProto NearbyPokemon = 11;
166 | }
167 |
168 | message MapPokemonProto {
169 | required string SpawnPointId = 1;
170 | required fixed64 EncounterId = 2;
171 | required int32 PokedexTypeId = 3;
172 | required int64 ExpirationTimeMs = 4;
173 | optional double Latitude = 5;
174 | optional double Longitude = 6;
175 | }
176 |
177 | message PokemonFortProto {
178 | required string FortId = 1;
179 | required int64 LastModifiedMs = 2;
180 | required double Latitude = 3;
181 | required double Longitude = 4;
182 | optional int32 Team = 5;
183 | optional int32 GuardPokemonId = 6;
184 | optional int32 GuardPokemonLevel = 7;
185 | required bool Enabled = 8;
186 | // ENUM.Holoholo.Rpc.FortType FortType = 9;
187 | optional int32 FortType = 9;
188 | optional int64 GymPoints = 10;
189 | optional bool IsInBattle = 11;
190 | optional bytes ActiveFortModifier = 12;
191 | optional FortLureInfoProto LureInfo = 13;
192 | optional int64 CooldownCompleteMs = 14;
193 | // ENUM.Holoholo.Rpc.Sponsor.Types.FortSponsor.Sponsor Sponsor = 15;
194 | optional int32 Sponsor = 15;
195 | // ENUM.Holoholo.Rpc.RenderingType.Types.FortRenderingType.RenderingType RenderingType = 16;
196 | optional int32 RenderingType = 16;
197 | }
198 |
199 | //based on : https://github.com/AHAAAAAAA/PokemonGo-Map/blob/master/pokemon.proto
200 | message FortLureInfoProto {
201 | required string FortId = 1;
202 | required double unknown2 = 2;
203 | required int32 ActivePokemonId = 3;
204 | required int64 LureExpiresTimestampMs = 4;
205 | optional string DeployerPlayerCodename = 5;
206 | }
207 |
208 | message PokemonSummaryFortProto {
209 | required string FortSummaryId = 1;
210 | required int64 LastModifiedMs = 2;
211 | required double Latitude = 3;
212 | required double Longitude = 4;
213 | }
214 |
215 | message ClientSpawnPointProto {
216 | required double Latitude = 2;
217 | required double Longitude = 3;
218 | }
219 |
220 | message WildPokemonProto {
221 | optional fixed64 EncounterId = 1;
222 | optional int64 LastModifiedMs = 2;
223 | optional double Latitude = 3;
224 | optional double Longitude = 4;
225 | optional string SpawnPointId = 5;
226 | optional Pokemon pokemon = 7;
227 | optional int32 TimeTillHiddenMs = 11;
228 |
229 | message Pokemon {
230 | optional uint64 Id = 1;
231 | optional PokemonId PokemonId = 2;
232 | optional int32 cp = 3;
233 | }
234 | }
235 |
236 | message NearbyPokemonProto {
237 | optional PokemonId PokedexNumber = 1;
238 | optional float DistanceMeters = 2;
239 | optional fixed64 EncounterId = 3;
240 | }
241 |
242 | message ProfilePayload {
243 | repeated int32 unknown1 = 1;
244 | optional Profile profile = 2;
245 | }
246 |
247 | message Profile {
248 | required int64 creation_time = 1;
249 | optional string username = 2;
250 | optional int32 team = 5;
251 | optional bytes tutorial = 7;
252 | optional AvatarDetails avatar = 8;
253 | optional int32 poke_storage = 9;
254 | optional int32 item_storage = 10;
255 | optional DailyBonus daily_bonus = 11;
256 | optional bytes unknown12 = 12;
257 | optional bytes unknown13 = 13;
258 | repeated Currency currency = 14;
259 |
260 | message AvatarDetails {
261 | optional int32 skin = 2;
262 | optional int32 hair = 3;
263 | optional int32 tshirt = 4;
264 | optional int32 trousers = 5;
265 | optional int32 cap = 6;
266 | optional int32 boots = 7;
267 | optional int32 gender = 8;
268 | optional int32 eyes = 9;
269 | optional int32 backpack = 10;
270 | }
271 |
272 | message DailyBonus {
273 | optional int64 NextCollectTimestampMs = 1;
274 | optional int64 NextDefenderBonusCollectTimestampMs = 2;
275 | }
276 |
277 | message Currency {
278 | required string type = 1;
279 | optional int32 amount = 2;
280 | }
281 | }
282 |
283 | message GetInventoryResponse {
284 | optional bool success = 1;
285 | optional InventoryDelta inventory_delta = 2;
286 | }
287 |
288 | message InventoryDelta {
289 | optional int64 original_timestamp_ms = 1;
290 | optional int64 new_timestamp_ms = 2;
291 | repeated InventoryItem inventory_items = 3;
292 | }
293 |
294 | message InventoryItem {
295 | optional int64 modified_timestamp_ms = 1;
296 | optional int64 deleted_item_key = 2;
297 | optional InventoryItemData inventory_item_data = 3;
298 | }
299 |
300 | message InventoryItemData {
301 | optional PokemonData pokemon = 1;
302 | optional Item item = 2;
303 | optional PokedexEntry pokedex_entry = 3;
304 | optional PlayerStats player_stats = 4;
305 | optional PlayerCurrency player_currency = 5;
306 | optional PlayerCamera player_camera = 6;
307 | optional InventoryUpgrades inventory_upgrades = 7;
308 | optional AppliedItems applied_items = 8;
309 | optional EggIncubators egg_incubators = 9;
310 | optional PokemonFamily pokemon_family = 10;
311 | }
312 |
313 | message PokemonData {
314 | optional fixed64 id = 1;
315 | optional PokemonId pokemon_id = 2;
316 | optional int32 cp = 3;
317 | optional int32 stamina = 4;
318 | optional int32 stamina_max = 5;
319 | optional PokemonMove move_1 = 6;
320 | optional PokemonMove move_2 = 7;
321 | optional string deployed_fort_id = 8;
322 | optional string owner_name = 9;
323 | optional bool is_egg = 10;
324 | optional double egg_km_walked_target = 11;
325 | optional double egg_km_walked_start = 12;
326 | optional int32 origin = 14;
327 | optional float height_m = 15;
328 | optional float weight_kg = 16;
329 | optional int32 individual_attack = 17;
330 | optional int32 individual_defense = 18;
331 | optional int32 individual_stamina = 19;
332 | optional float cp_multiplier = 20;
333 | optional ItemId pokeball = 21;
334 | optional uint64 captured_cell_id = 22;
335 | optional int32 battles_attacked = 23;
336 | optional int32 battles_defended = 24;
337 | optional string egg_incubator_id = 25;
338 | optional uint64 creation_time_ms = 26;
339 | optional int32 num_upgrades = 27;
340 | optional float additional_cp_multiplier = 28;
341 | optional int32 favorite = 29;
342 | optional string nickname = 30;
343 | optional int32 from_fort = 31;
344 | }
345 |
346 | message Pokemon {
347 | optional int32 id = 1;
348 | optional PokemonId pokemon_type = 2;
349 | optional int32 cp = 3;
350 | optional int32 stamina = 4;
351 | optional int32 stamina_max = 5;
352 | optional PokemonMove move_1 = 6;
353 | optional PokemonMove move_2 = 7;
354 | optional int32 deployed_fort_id = 8;
355 | optional string owner_name = 9;
356 | optional bool is_egg = 10;
357 | optional int32 egg_km_walked_target = 11;
358 | optional int32 egg_km_walked_start = 12;
359 | optional int32 origin = 14;
360 | optional float height_m = 15;
361 | optional float weight_kg = 16;
362 | optional int32 individual_attack = 17;
363 | optional int32 individual_defense = 18;
364 | optional int32 individual_stamina = 19;
365 | optional int32 cp_multiplier = 20;
366 | optional int32 pokeball = 21;
367 | optional uint64 captured_cell_id = 22;
368 | optional int32 battles_attacked = 23;
369 | optional int32 battles_defended = 24;
370 | optional int32 egg_incubator_id = 25;
371 | optional uint64 creation_time_ms = 26;
372 | optional int32 num_upgrades = 27;
373 | optional int32 additional_cp_multiplier = 28;
374 | optional int32 favorite = 29;
375 | optional string nickname = 30;
376 | optional int32 from_fort = 31;
377 | }
378 |
379 | enum TeamColor {
380 | NEUTRAL = 0;
381 | BLUE = 1;
382 | RED = 2;
383 | YELLOW = 3;
384 | }
385 |
386 | enum PokemonMove {
387 | MOVE_UNSET = 0;
388 | THUNDER_SHOCK = 1;
389 | QUICK_ATTACK = 2;
390 | SCRATCH = 3;
391 | EMBER = 4;
392 | VINE_WHIP = 5;
393 | TACKLE = 6;
394 | RAZOR_LEAF = 7;
395 | TAKE_DOWN = 8;
396 | WATER_GUN = 9;
397 | BITE = 10;
398 | POUND = 11;
399 | DOUBLE_SLAP = 12;
400 | WRAP = 13;
401 | HYPER_BEAM = 14;
402 | LICK = 15;
403 | DARK_PULSE = 16;
404 | SMOG = 17;
405 | SLUDGE = 18;
406 | METAL_CLAW = 19;
407 | VICE_GRIP = 20;
408 | FLAME_WHEEL = 21;
409 | MEGAHORN = 22;
410 | WING_ATTACK = 23;
411 | FLAMETHROWER = 24;
412 | SUCKER_PUNCH = 25;
413 | DIG = 26;
414 | LOW_KICK = 27;
415 | CROSS_CHOP = 28;
416 | PSYCHO_CUT = 29;
417 | PSYBEAM = 30;
418 | EARTHQUAKE = 31;
419 | STONE_EDGE = 32;
420 | ICE_PUNCH = 33;
421 | HEART_STAMP = 34;
422 | DISCHARGE = 35;
423 | FLASH_CANNON = 36;
424 | PECK = 37;
425 | DRILL_PECK = 38;
426 | ICE_BEAM = 39;
427 | BLIZZARD = 40;
428 | AIR_SLASH = 41;
429 | HEAT_WAVE = 42;
430 | TWINEEDLE = 43;
431 | POISON_JAB = 44;
432 | AERIAL_ACE = 45;
433 | DRILL_RUN = 46;
434 | PETAL_BLIZZARD = 47;
435 | MEGA_DRAIN = 48;
436 | BUG_BUZZ = 49;
437 | POISON_FANG = 50;
438 | NIGHT_SLASH = 51;
439 | SLASH = 52;
440 | BUBBLE_BEAM = 53;
441 | SUBMISSION = 54;
442 | KARATE_CHOP = 55;
443 | LOW_SWEEP = 56;
444 | AQUA_JET = 57;
445 | AQUA_TAIL = 58;
446 | SEED_BOMB = 59;
447 | PSYSHOCK = 60;
448 | ROCK_THROW = 61;
449 | ANCIENT_POWER = 62;
450 | ROCK_TOMB = 63;
451 | ROCK_SLIDE = 64;
452 | POWER_GEM = 65;
453 | SHADOW_SNEAK = 66;
454 | SHADOW_PUNCH = 67;
455 | SHADOW_CLAW = 68;
456 | OMINOUS_WIND = 69;
457 | SHADOW_BALL = 70;
458 | BULLET_PUNCH = 71;
459 | MAGNET_BOMB = 72;
460 | STEEL_WING = 73;
461 | IRON_HEAD = 74;
462 | PARABOLIC_CHARGE = 75;
463 | SPARK = 76;
464 | THUNDER_PUNCH = 77;
465 | THUNDER = 78;
466 | THUNDERBOLT = 79;
467 | TWISTER = 80;
468 | DRAGON_BREATH = 81;
469 | DRAGON_PULSE = 82;
470 | DRAGON_CLAW = 83;
471 | DISARMING_VOICE = 84;
472 | DRAINING_KISS = 85;
473 | DAZZLING_GLEAM = 86;
474 | MOONBLAST = 87;
475 | PLAY_ROUGH = 88;
476 | CROSS_POISON = 89;
477 | SLUDGE_BOMB = 90;
478 | SLUDGE_WAVE = 91;
479 | GUNK_SHOT = 92;
480 | MUD_SHOT = 93;
481 | BONE_CLUB = 94;
482 | BULLDOZE = 95;
483 | MUD_BOMB = 96;
484 | FURY_CUTTER = 97;
485 | BUG_BITE = 98;
486 | SIGNAL_BEAM = 99;
487 | X_SCISSOR = 100;
488 | FLAME_CHARGE = 101;
489 | FLAME_BURST = 102;
490 | FIRE_BLAST = 103;
491 | BRINE = 104;
492 | WATER_PULSE = 105;
493 | SCALD = 106;
494 | HYDRO_PUMP = 107;
495 | PSYCHIC = 108;
496 | PSYSTRIKE = 109;
497 | ICE_SHARD = 110;
498 | ICY_WIND = 111;
499 | FROST_BREATH = 112;
500 | ABSORB = 113;
501 | GIGA_DRAIN = 114;
502 | FIRE_PUNCH = 115;
503 | SOLAR_BEAM = 116;
504 | LEAF_BLADE = 117;
505 | POWER_WHIP = 118;
506 | SPLASH = 119;
507 | ACID = 120;
508 | AIR_CUTTER = 121;
509 | HURRICANE = 122;
510 | BRICK_BREAK = 123;
511 | CUT = 124;
512 | SWIFT = 125;
513 | HORN_ATTACK = 126;
514 | STOMP = 127;
515 | HEADBUTT = 128;
516 | HYPER_FANG = 129;
517 | SLAM = 130;
518 | BODY_SLAM = 131;
519 | REST = 132;
520 | STRUGGLE = 133;
521 | SCALD_BLASTOISE = 134;
522 | HYDRO_PUMP_BLASTOISE = 135;
523 | WRAP_GREEN = 136;
524 | WRAP_PINK = 137;
525 | FURY_CUTTER_FAST = 200;
526 | BUG_BITE_FAST = 201;
527 | BITE_FAST = 202;
528 | SUCKER_PUNCH_FAST = 203;
529 | DRAGON_BREATH_FAST = 204;
530 | THUNDER_SHOCK_FAST = 205;
531 | SPARK_FAST = 206;
532 | LOW_KICK_FAST = 207;
533 | KARATE_CHOP_FAST = 208;
534 | EMBER_FAST = 209;
535 | WING_ATTACK_FAST = 210;
536 | PECK_FAST = 211;
537 | LICK_FAST = 212;
538 | SHADOW_CLAW_FAST = 213;
539 | VINE_WHIP_FAST = 214;
540 | RAZOR_LEAF_FAST = 215;
541 | MUD_SHOT_FAST = 216;
542 | ICE_SHARD_FAST = 217;
543 | FROST_BREATH_FAST = 218;
544 | QUICK_ATTACK_FAST = 219;
545 | SCRATCH_FAST = 220;
546 | TACKLE_FAST = 221;
547 | POUND_FAST = 222;
548 | CUT_FAST = 223;
549 | POISON_JAB_FAST = 224;
550 | ACID_FAST = 225;
551 | PSYCHO_CUT_FAST = 226;
552 | ROCK_THROW_FAST = 227;
553 | METAL_CLAW_FAST = 228;
554 | BULLET_PUNCH_FAST = 229;
555 | WATER_GUN_FAST = 230;
556 | SPLASH_FAST = 231;
557 | WATER_GUN_FAST_BLASTOISE = 232;
558 | MUD_SLAP_FAST = 233;
559 | ZEN_HEADBUTT_FAST = 234;
560 | CONFUSION_FAST = 235;
561 | POISON_STING_FAST = 236;
562 | BUBBLE_FAST = 237;
563 | FEINT_ATTACK_FAST = 238;
564 | STEEL_WING_FAST = 239;
565 | FIRE_FANG_FAST = 240;
566 | ROCK_SMASH_FAST = 241;
567 | }
568 |
569 | enum PokemonId {
570 | MISSINGNO = 0;
571 | BULBASAUR = 1;
572 | IVYSAUR = 2;
573 | VENUSAUR = 3;
574 | CHARMENDER = 4;
575 | CHARMELEON = 5;
576 | CHARIZARD = 6;
577 | SQUIRTLE = 7;
578 | WARTORTLE = 8;
579 | BLASTOISE = 9;
580 | CATERPIE = 10;
581 | METAPOD = 11;
582 | BUTTERFREE = 12;
583 | WEEDLE = 13;
584 | KAKUNA = 14;
585 | BEEDRILL = 15;
586 | PIDGEY = 16;
587 | PIDGEOTTO = 17;
588 | PIDGEOT = 18;
589 | RATTATA = 19;
590 | RATICATE = 20;
591 | SPEAROW = 21;
592 | FEAROW = 22;
593 | EKANS = 23;
594 | ARBOK = 24;
595 | PIKACHU = 25;
596 | RAICHU = 26;
597 | SANDSHREW = 27;
598 | SANDLASH = 28;
599 | NIDORAN_FEMALE = 29;
600 | NIDORINA = 30;
601 | NIDOQUEEN = 31;
602 | NIDORAN_MALE = 32;
603 | NIDORINO = 33;
604 | NIDOKING = 34;
605 | CLEFARY = 35;
606 | CLEFABLE = 36;
607 | VULPIX = 37;
608 | NINETALES = 38;
609 | JIGGLYPUFF = 39;
610 | WIGGLYTUFF = 40;
611 | ZUBAT = 41;
612 | GOLBAT = 42;
613 | ODDISH = 43;
614 | GLOOM = 44;
615 | VILEPLUME = 45;
616 | PARAS = 46;
617 | PARASECT = 47;
618 | VENONAT = 48;
619 | VENOMOTH = 49;
620 | DIGLETT = 50;
621 | DUGTRIO = 51;
622 | MEOWTH = 52;
623 | PERSIAN = 53;
624 | PSYDUCK = 54;
625 | GOLDUCK = 55;
626 | MANKEY = 56;
627 | PRIMEAPE = 57;
628 | GROWLITHE = 58;
629 | ARCANINE = 59;
630 | POLIWAG = 60;
631 | POLIWHIRL = 61;
632 | POLIWRATH = 62;
633 | ABRA = 63;
634 | KADABRA = 64;
635 | ALAKHAZAM = 65;
636 | MACHOP = 66;
637 | MACHOKE = 67;
638 | MACHAMP = 68;
639 | BELLSPROUT = 69;
640 | WEEPINBELL = 70;
641 | VICTREEBELL = 71;
642 | TENTACOOL = 72;
643 | TENTACRUEL = 73;
644 | GEODUGE = 74;
645 | GRAVELER = 75;
646 | GOLEM = 76;
647 | PONYTA = 77;
648 | RAPIDASH = 78;
649 | SLOWPOKE = 79;
650 | SLOWBRO = 80;
651 | MAGNEMITE = 81;
652 | MAGNETON = 82;
653 | FARFETCHD = 83;
654 | DODUO = 84;
655 | DODRIO = 85;
656 | SEEL = 86;
657 | DEWGONG = 87;
658 | GRIMER = 88;
659 | MUK = 89;
660 | SHELLDER = 90;
661 | CLOYSTER = 91;
662 | GASTLY = 92;
663 | HAUNTER = 93;
664 | GENGAR = 94;
665 | ONIX = 95;
666 | DROWZEE = 96;
667 | HYPNO = 97;
668 | KRABBY = 98;
669 | KINGLER = 99;
670 | VOLTORB = 100;
671 | ELECTRODE = 101;
672 | EXEGGCUTE = 102;
673 | EXEGGUTOR = 103;
674 | CUBONE = 104;
675 | MAROWAK = 105;
676 | HITMONLEE = 106;
677 | HITMONCHAN = 107;
678 | LICKITUNG = 108;
679 | KOFFING = 109;
680 | WEEZING = 110;
681 | RHYHORN = 111;
682 | RHYDON = 112;
683 | CHANSEY = 113;
684 | TANGELA = 114;
685 | KANGASKHAN = 115;
686 | HORSEA = 116;
687 | SEADRA = 117;
688 | GOLDEEN = 118;
689 | SEAKING = 119;
690 | STARYU = 120;
691 | STARMIE = 121;
692 | MR_MIME = 122;
693 | SCYTHER = 123;
694 | JYNX = 124;
695 | ELECTABUZZ = 125;
696 | MAGMAR = 126;
697 | PINSIR = 127;
698 | TAUROS = 128;
699 | MAGIKARP = 129;
700 | GYARADOS = 130;
701 | LAPRAS = 131;
702 | DITTO = 132;
703 | EEVEE = 133;
704 | VAPOREON = 134;
705 | JOLTEON = 135;
706 | FLAREON = 136;
707 | PORYGON = 137;
708 | OMANYTE = 138;
709 | OMASTAR = 139;
710 | KABUTO = 140;
711 | KABUTOPS = 141;
712 | AERODACTYL = 142;
713 | SNORLAX = 143;
714 | ARTICUNO = 144;
715 | ZAPDOS = 145;
716 | MOLTRES = 146;
717 | DRATINI = 147;
718 | DRAGONAIR = 148;
719 | DRAGONITE = 149;
720 | MEWTWO = 150;
721 | MEW = 151;
722 | }
723 |
724 | message Item {
725 | optional ItemId item_id = 1;
726 | optional int32 count = 2;
727 | optional bool unseen = 3;
728 | }
729 |
730 | enum ItemType {
731 | ITEM_TYPE_NONE = 0;
732 | ITEM_TYPE_POKEBALL = 1;
733 | ITEM_TYPE_POTION = 2;
734 | ITEM_TYPE_REVIVE = 3;
735 | ITEM_TYPE_MAP = 4;
736 | ITEM_TYPE_BATTLE = 5;
737 | ITEM_TYPE_FOOD = 6;
738 | ITEM_TYPE_CAMERA = 7;
739 | ITEM_TYPE_DISK = 8;
740 | ITEM_TYPE_INCUBATOR = 9;
741 | ITEM_TYPE_INCENSE = 10;
742 | ITEM_TYPE_XP_BOOST = 11;
743 | ITEM_TYPE_INVENTORY_UPGRADE = 12;
744 | }
745 |
746 | message PokedexEntry {
747 | optional int32 pokedex_entry_number = 1;
748 | optional int32 times_encountered = 2;
749 | optional int32 times_captured = 3;
750 | optional int32 evolution_stone_pieces = 4;
751 | optional int32 evolution_stones = 5;
752 | }
753 |
754 | message PlayerStats {
755 | optional int32 level = 1;
756 | optional int64 experience = 2;
757 | optional int64 prev_level_xp = 3;
758 | optional int64 next_level_xp = 4;
759 | optional float km_walked = 5;
760 | optional int32 pokemons_encountered = 6;
761 | optional int32 unique_pokedex_entries = 7;
762 | optional int32 pokemons_captured = 8;
763 | optional int32 evolutions = 9;
764 | optional int32 poke_stop_visits = 10;
765 | optional int32 pokeballs_thrown = 11;
766 | optional int32 eggs_hatched = 12;
767 | optional int32 big_magikarp_caught = 13;
768 | optional int32 battle_attack_won = 14;
769 | optional int32 battle_attack_total = 15;
770 | optional int32 battle_defended_won = 16;
771 | optional int32 battle_training_won = 17;
772 | optional int32 battle_training_total = 18;
773 | optional int32 prestige_raised_total = 19;
774 | optional int32 prestige_dropped_total = 20;
775 | optional int32 pokemon_deployed = 21;
776 | optional bytes pokemon_caught_by_type = 22; // TODO: repeated PokemonType ??
777 | optional int32 small_rattata_caught = 23;
778 | }
779 |
780 | message PlayerCurrency {
781 | optional int32 gems = 1;
782 | }
783 |
784 | message PlayerCamera {
785 | optional bool is_default_camera = 1;
786 | }
787 |
788 | message InventoryUpgrades {
789 | repeated InventoryUpgrade inventory_upgrades = 1;
790 | }
791 |
792 | message InventoryUpgrade {
793 | optional ItemType item = 1;
794 | optional InventoryUpgradeType upgrade_type = 2;
795 | optional int32 additional_storage = 3;
796 | }
797 |
798 | enum InventoryUpgradeType {
799 | UPGRADE_UNSET = 0;
800 | INCREASE_ITEM_STORAGE = 1;
801 | INCREASE_POKEMON_STORAGE = 2;
802 | }
803 |
804 | message AppliedItems {
805 | optional AppliedItem item = 4;
806 | }
807 |
808 | message AppliedItem {
809 | optional ItemId item_type = 1;
810 | optional ItemType item_type_category = 2;
811 | optional int64 expire_ms = 3;
812 | optional int64 applied_ms = 4;
813 | }
814 |
815 | enum ItemId {
816 | ITEM_UNKNOWN = 0;
817 | ITEM_POKE_BALL = 1;
818 | ITEM_GREAT_BALL = 2;
819 | ITEM_ULTRA_BALL = 3;
820 | ITEM_MASTER_BALL = 4;
821 | ITEM_POTION = 101;
822 | ITEM_SUPER_POTION = 102;
823 | ITEM_HYPER_POTION = 103;
824 | ITEM_MAX_POTION = 104;
825 | ITEM_REVIVE = 201;
826 | ITEM_MAX_REVIVE = 202;
827 | ITEM_LUCKY_EGG = 301;
828 | ITEM_INCENSE_ORDINARY = 401;
829 | ITEM_INCENSE_SPICY = 402;
830 | ITEM_INCENSE_COOL = 403;
831 | ITEM_INCENSE_FLORAL = 404;
832 | ITEM_TROY_DISK = 501;
833 | ITEM_X_ATTACK = 602;
834 | ITEM_X_DEFENSE = 603;
835 | ITEM_X_MIRACLE = 604;
836 | ITEM_RAZZ_BERRY = 701;
837 | ITEM_BLUK_BERRY = 702;
838 | ITEM_NANAB_BERRY = 703;
839 | ITEM_WEPAR_BERRY = 704;
840 | ITEM_PINAP_BERRY = 705;
841 | ITEM_SPECIAL_CAMERA = 801;
842 | ITEM_INCUBATOR_BASIC_UNLIMITED = 901;
843 | ITEM_INCUBATOR_BASIC = 902;
844 | ITEM_POKEMON_STORAGE_UPGRADE = 1001;
845 | ITEM_ITEM_STORAGE_UPGRADE = 1002;
846 | }
847 |
848 | message EggIncubators {
849 | repeated EggIncubator egg_incubator = 1;
850 | }
851 |
852 | message EggIncubator {
853 | optional string item_id = 1;
854 | optional ItemType item_type = 2;
855 | optional EggIncubatorType incubator_type = 3;
856 | optional int32 uses_remaining = 4;
857 | optional int64 pokemon_id = 5; // TODO: Check if is PokemonType
858 | optional double start_km_walked = 6;
859 | optional double target_km_walked = 7;
860 | }
861 |
862 | enum EggIncubatorType {
863 | INCUBATOR_UNSET = 0;
864 | INCUBATOR_DISTANCE = 1;
865 | }
866 |
867 | message PokemonFamily {
868 | optional PokemonFamilyId family_id = 1;
869 | optional int32 candy = 2;
870 | }
871 |
872 | enum PokemonFamilyId {
873 | FAMILY_UNSET = 0;
874 | FAMILY_BULBASAUR = 1;
875 | FAMILY_CHARMANDER = 4;
876 | FAMILY_SQUIRTLE = 7;
877 | FAMILY_CATERPIE = 10;
878 | FAMILY_WEEDLE = 13;
879 | FAMILY_PIDGEY = 16;
880 | FAMILY_RATTATA = 19;
881 | FAMILY_SPEAROW = 21;
882 | FAMILY_EKANS = 23;
883 | FAMILY_PIKACHU = 25;
884 | FAMILY_SANDSHREW = 27;
885 | FAMILY_NIDORAN = 29;
886 | FAMILY_NIDORAN2 = 32;
887 | FAMILY_CLEFAIRY = 35;
888 | FAMILY_VULPIX = 37;
889 | FAMILY_JIGGLYPUFF = 39;
890 | FAMILY_ZUBAT = 41;
891 | FAMILY_ODDISH = 43;
892 | FAMILY_PARAS = 46;
893 | FAMILY_VENONAT = 48;
894 | FAMILY_DIGLETT = 50;
895 | FAMILY_MEOWTH = 52;
896 | FAMILY_PSYDUCK = 54;
897 | FAMILY_MANKEY = 56;
898 | FAMILY_GROWLITHE = 58;
899 | FAMILY_POLIWAG = 60;
900 | FAMILY_ABRA = 63;
901 | FAMILY_MACHOP = 66;
902 | FAMILY_BELLSPROUT = 69;
903 | FAMILY_TENTACOOL = 72;
904 | FAMILY_GEODUDE = 74;
905 | FAMILY_PONYTA = 77;
906 | FAMILY_SLOWPOKE = 79;
907 | FAMILY_MAGNEMITE = 81;
908 | FAMILY_FARFETCHD = 83;
909 | FAMILY_DODUO = 84;
910 | FAMILY_SEEL = 86;
911 | FAMILY_GRIMER = 88;
912 | FAMILY_SHELLDER = 90;
913 | FAMILY_GASTLY = 92;
914 | FAMILY_ONIX = 95;
915 | FAMILY_DROWZEE = 96;
916 | FAMILY_KRABBY = 98;
917 | FAMILY_VOLTORB = 100;
918 | FAMILY_EXEGGCUTE = 102;
919 | FAMILY_CUBONE = 104;
920 | FAMILY_HITMONLEE = 106;
921 | FAMILY_HITMONCHAN = 107;
922 | FAMILY_LICKITUNG = 108;
923 | FAMILY_KOFFING = 109;
924 | FAMILY_RHYHORN = 111;
925 | FAMILY_CHANSEY = 113;
926 | FAMILY_TANGELA = 114;
927 | FAMILY_KANGASKHAN = 115;
928 | FAMILY_HORSEA = 116;
929 | FAMILY_GOLDEEN = 118;
930 | FAMILY_STARYU = 120;
931 | FAMILY_MR_MIME = 122;
932 | FAMILY_SCYTHER = 123;
933 | FAMILY_JYNX = 124;
934 | FAMILY_ELECTABUZZ = 125;
935 | FAMILY_MAGMAR = 126;
936 | FAMILY_PINSIR = 127;
937 | FAMILY_TAUROS = 128;
938 | FAMILY_MAGIKARP = 129;
939 | FAMILY_LAPRAS = 131;
940 | FAMILY_DITTO = 132;
941 | FAMILY_EEVEE = 133;
942 | FAMILY_PORYGON = 137;
943 | FAMILY_OMANYTE = 138;
944 | FAMILY_KABUTO = 140;
945 | FAMILY_AERODACTYL = 142;
946 | FAMILY_SNORLAX = 143;
947 | FAMILY_ARTICUNO = 144;
948 | FAMILY_ZAPDOS = 145;
949 | FAMILY_MOLTRES = 146;
950 | FAMILY_DRATINI = 147;
951 | FAMILY_MEWTWO = 150;
952 | FAMILY_MEW = 151;
953 | }
954 |
955 | enum FortType {
956 | GYM = 0;
957 | CHECKPOINT = 1;
958 | }
959 |
960 | message CatchPokemonResponse {
961 | required CatchStatus Status = 1;
962 | optional double MissPercent = 2;
963 | //optional uint64 CapturedPokemonId = 3;
964 | //optional CaptureAward CaptureAward = 4;
965 |
966 | enum CatchStatus {
967 | CATCH_ERROR = 0;
968 | CATCH_SUCCESS = 1;
969 | CATCH_ESCAPE = 2;
970 | CATCH_FLEE = 3;
971 | CATCH_MISSED = 4;
972 | }
973 | }
974 |
975 | enum ActivityType {
976 | ACTIVITY_UNKNOWN = 0;
977 | ACTIVITY_CATCH_POKEMON = 1;
978 | ACTIVITY_CATCH_LEGEND_POKEMON = 2;
979 | ACTIVITY_FLEE_POKEMON = 3;
980 | ACTIVITY_DEFEAT_FORT = 4;
981 | ACTIVITY_EVOLVE_POKEMON = 5;
982 | ACTIVITY_HATCH_EGG = 6;
983 | ACTIVITY_WALK_KM = 7;
984 | ACTIVITY_POKEDEX_ENTRY_NEW = 8;
985 | ACTIVITY_CATCH_FIRST_THROW = 9;
986 | ACTIVITY_CATCH_NICE_THROW = 10;
987 | ACTIVITY_CATCH_GREAT_THROW = 11;
988 | ACTIVITY_CATCH_EXCELLENT_THROW = 12;
989 | ACTIVITY_CATCH_CURVEBALL = 13;
990 | ACTIVITY_CATCH_FIRST_CATCH_OF_DAY = 14;
991 | ACTIVITY_CATCH_MILESTONE = 15;
992 | ACTIVITY_TRAIN_POKEMON = 16;
993 | ACTIVITY_SEARCH_FORT = 17;
994 | ACTIVITY_RELEASE_POKEMON = 18;
995 | ACTIVITY_HATCH_EGG_SMALL_BONUS = 19;
996 | ACTIVITY_HATCH_EGG_MEDIUM_BONUS = 20;
997 | ACTIVITY_HATCH_EGG_LARGE_BONUS = 21;
998 | ACTIVITY_DEFEAT_GYM_DEFENDER = 22;
999 | ACTIVITY_DEFEAT_GYM_LEADER = 23;
1000 | }
1001 |
1002 | message CaptureAward {
1003 | repeated ActivityType ActivityType = 1 [packed=true];
1004 | repeated int32 XP = 2 [packed=true];
1005 | repeated int32 Candy = 3 [packed=true];
1006 | repeated int32 Stardust = 4 [packed=true];
1007 | }
1008 |
1009 | message CaptureProbability {
1010 | repeated ItemId PokeballType = 1;
1011 | repeated float CaptureProbability = 2;
1012 | optional float ReticleDifficultySize = 12;
1013 | }
1014 |
1015 | message EncounterResponse {
1016 | optional WildPokemonProto WildPokemon = 1;
1017 | optional Background EncounterBackground = 2;
1018 | optional Status EncounterStatus = 3;
1019 | //optional CaptureProbability EncounterCaptureProbability = 4;
1020 |
1021 | enum Background {
1022 | PARK = 0;
1023 | DESERT = 1;
1024 | }
1025 |
1026 | enum Status {
1027 | ENCOUNTER_ERROR = 0;
1028 | ENCOUNTER_SUCCESS = 1;
1029 | ENCOUNTER_NOT_FOUND = 2;
1030 | ENCOUNTER_CLOSED = 3;
1031 | ENCOUNTER_POKEMON_FLED = 4;
1032 | ENCOUNTER_NOT_IN_RANGE = 5;
1033 | ENCOUNTER_ALREADY_HAPPENED = 6;
1034 | POKEMON_INVENTORY_FULL = 7;
1035 | }
1036 | }
1037 |
1038 | message FortSearchResponse {
1039 | optional Result result = 1;
1040 | repeated ItemAward items_awarded = 2;
1041 | optional int32 gems_awarded = 3;
1042 | optional PokemonData pokemon_data_egg = 4;
1043 | optional int32 experience_awarded = 5;
1044 | optional int64 cooldown_complete_timestamp_ms = 6;
1045 | optional int32 chain_hack_sequence_number = 7;
1046 |
1047 | enum Result {
1048 | NO_RESULT_SET = 0;
1049 | SUCCESS = 1;
1050 | OUT_OF_RANGE = 2;
1051 | IN_COOLDOWN_PERIOD = 3;
1052 | INVENTORY_FULL = 4;
1053 | }
1054 | }
1055 |
1056 | message FortDetailsResponse {
1057 | optional string fort_id = 1;
1058 | optional TeamColor team_color = 2;
1059 | optional PokemonData pokemon_data = 3;
1060 | optional string name = 4;
1061 | repeated string image_urls = 5;
1062 | optional int32 fp = 6;
1063 | optional int32 stamina = 7;
1064 | optional int32 max_stamina = 8;
1065 | optional int32 type = 9;
1066 | optional double latitude = 10;
1067 | optional double longitude = 11;
1068 | optional string description = 12;
1069 | repeated FortModifier modifiers = 13;
1070 | }
1071 |
1072 | message FortModifier {
1073 | optional ItemId item_id = 1;
1074 | optional int64 expiration_timestamp_ms = 2;
1075 | optional string deployer_player_codename = 3;
1076 | }
1077 |
1078 | message RecycleInventoryItemResponse {
1079 | optional Result result = 1;
1080 | optional int32 new_count = 2;
1081 |
1082 | enum Result {
1083 | UNSET = 0;
1084 | SUCCESS = 1;
1085 | ERROR_NOT_ENOUGH_COPIES = 2;
1086 | ERROR_CANNOT_RECYCLE_INCUBATORS = 3;
1087 | }
1088 | }
1089 |
1090 | message ItemAward {
1091 | optional ItemId item_id = 1;
1092 | optional int32 item_count = 2;
1093 | }
1094 |
1095 | message ReleasePokemonResponse {
1096 | required ReleaseStatus Status = 1;
1097 | optional int32 CandyAwarded = 2;
1098 | enum ReleaseStatus {
1099 | UNSET = 0;
1100 | SUCCESS = 1;
1101 | POKEMON_DEPLOYED = 2;
1102 | FAILED = 3;
1103 | ERROR_POKEMON_IS_EGG = 4;
1104 | }
1105 | }
1106 |
1107 | message EvolvePokemonResponse
1108 | {
1109 | optional EvolvePokemonStatus Result = 1;
1110 | optional Pokemon EvolvedPokemon = 2;
1111 | optional int32 ExpAwarded = 3;
1112 | optional int32 CandyAwarded = 4;
1113 |
1114 | enum EvolvePokemonStatus {
1115 | POKEMON_EVOLVED_UNSET = 0;
1116 | POKEMON_EVOLVED_SUCCESS = 1;
1117 | FAILED_POKEMON_MISSING = 2;
1118 | FAILED_INSUFFICIENT_RESOURCES = 3;
1119 | FAILED_POKEMON_CANNOT_EVOLVE = 4;
1120 | FAILED_POKEMON_IS_DEPLOYED = 5;
1121 | }
1122 | }
1123 |
1124 | message TransferPokemonResponse {
1125 | optional int32 Status = 1;
1126 | optional int32 CandyAwarded = 2;
1127 | }
1128 |
1129 | message LevelUpRewardsResponse {
1130 | required RewardStatus Status = 1;
1131 | repeated ItemAward items_awarded = 2;
1132 | repeated ItemId items_unlocked = 4;
1133 |
1134 | enum RewardStatus {
1135 | UNSET = 0;
1136 | SUCCESS = 1;
1137 | AWARDED_ALREADY = 2;
1138 | }
1139 | }
1140 |
1141 | message UseItemEggIncubatorResponse {
1142 | required IncubatorStatus Status = 1;
1143 | required EggIncubator egg_incubator = 2;
1144 |
1145 | enum IncubatorStatus {
1146 | UNSET = 0;
1147 | SUCCESS = 1;
1148 | ERROR_INCUBATOR_NOT_FOUND = 2;
1149 | ERROR_POKEMON_EGG_NOT_FOUND = 3;
1150 | ERROR_POKEMON_ID_NOT_EGG = 4;
1151 | ERROR_INCUBATOR_ALREADY_IN_USE = 5;
1152 | ERROR_POKEMON_ALREADY_INCUBATING = 6;
1153 | ERROR_INCUBATOR_NO_USES_REMAINING = 7;
1154 | }
1155 | }
1156 |
1157 | message GetHatchedEggsResponse {
1158 | required bool success = 1;
1159 | repeated uint64 pokemon_id = 2 [packed=true];
1160 | repeated int32 experience_awarded = 3;
1161 | repeated int32 candy_awarded = 4;
1162 | repeated int32 stardust_awarded = 5;
1163 | }
1164 |
1165 | message UseItemXpBoostResponse {
1166 | required XpBoostStatus Status = 1;
1167 | optional AppliedItems applied_items = 2;
1168 |
1169 | enum XpBoostStatus {
1170 | UNSET = 0;
1171 | SUCCESS = 1;
1172 | ERROR_INVALID_ITEM_TYPE = 2;
1173 | ERROR_XP_BOOST_ALREADY_ACTIVE = 3;
1174 | ERROR_NO_ITEMS_REMAINING = 4;
1175 | ERROR_LOCATION_UNSET = 5;
1176 | }
1177 | }
1178 |
1179 | }
1180 |
1181 | message Signature {
1182 |
1183 | message LocationFix {
1184 | optional string provider = 1; // "network", "gps", "fused", possibly others
1185 | optional uint64 timestamp_since_start = 2; // in ms
1186 | optional float latitude = 13;
1187 | optional float longitude = 14;
1188 |
1189 | // ??? shows up in struct, dunno where these go
1190 | // float device_speed;
1191 | // float device_course;
1192 | optional float horizontal_accuracy = 20; // iOS only? (range seems to be -1 to +1)
1193 | optional float altitude = 21;
1194 | optional float vertical_accuracy = 22; // iOS only? (range seems to be ~10-12)
1195 | optional uint64 provider_status = 26; // Usually 3 (possibly GPS status: 1 = no fix, 2 = acquiring/inaccurate, 3 = fix acquired)
1196 | optional uint32 floor = 27; // No idea what this is, seems to be optional
1197 | optional uint64 location_type = 28; // Always 1 (if there is data at all)
1198 | }
1199 |
1200 | // don't really care about this since we're not using it
1201 | message AndroidGpsInfo {
1202 | optional uint64 time_to_fix = 1;
1203 | repeated int32 satellites_prn = 2;
1204 | repeated float snr = 3;
1205 | repeated float azimuth = 4;
1206 | repeated float elevation = 5;
1207 | repeated bool has_almanac = 6;
1208 | repeated bool has_ephemeris = 7;
1209 | repeated bool used_in_fix = 8;
1210 | }
1211 |
1212 | message SensorInfo {
1213 | optional uint64 timestamp_snapshot = 1; // in ms
1214 | optional double magnetometer_x = 3;
1215 | optional double magnetometer_y = 4;
1216 | optional double magnetometer_z = 5;
1217 | optional double angle_normalized_x = 6;
1218 | optional double angle_normalized_y = 7;
1219 | optional double angle_normalized_z = 8;
1220 | optional double accel_raw_x = 10;
1221 | optional double accel_raw_y = 11;
1222 | optional double accel_raw_z = 12;
1223 | optional double gyroscope_raw_x = 13;
1224 | optional double gyroscope_raw_y = 14;
1225 | optional double gyroscope_raw_z = 15;
1226 | optional double accel_normalized_x = 16;
1227 | optional double accel_normalized_y = 17;
1228 | optional double accel_normalized_z = 18;
1229 | optional uint64 accelerometer_axes = 19; // Always 3
1230 | }
1231 |
1232 | message DeviceInfo {
1233 | optional string device_id = 1; // Hex string
1234 | optional string android_board_name = 2;
1235 | optional string android_bootloader = 3;
1236 | optional string device_brand = 4; // On Android: product.brand
1237 | optional string device_model = 5; // On Android: product.device
1238 | optional string device_model_identifier = 6; // Android only, build.display.id
1239 | optional string device_model_boot = 7; // On Android: boot.hardware
1240 | optional string hardware_manufacturer = 8; // On Android: product.manufacturer
1241 | optional string hardware_model = 9; // On Android: product.model
1242 | optional string firmware_brand = 10; // On Android: product.name, on iOS: "iPhone OS"
1243 | optional string firmware_tags = 12; // Android only, build.tags
1244 | optional string firmware_type = 13; // On Android: build.type, on iOS instead: iOS version
1245 | optional string firmware_fingerprint = 14; // Android only, build.fingerprint
1246 | }
1247 |
1248 | message ActivityStatus {
1249 | // all of these had 1 as their value
1250 | optional uint64 start_time_ms = 1;
1251 | optional bool unknown_status = 2;
1252 | optional bool walking = 3;
1253 | optional bool running = 4;
1254 | optional bool stationary = 5;
1255 | optional bool automotive = 6;
1256 | optional bool tilting = 7;
1257 | optional bool cycling = 8;
1258 | optional bytes status = 9;
1259 | }
1260 |
1261 | optional uint64 timestamp_since_start = 2; // in ms
1262 | repeated LocationFix location_fix = 4;
1263 | optional AndroidGpsInfo gps_info = 5;
1264 | optional SensorInfo sensor_info = 7;
1265 | optional DeviceInfo device_info = 8;
1266 | optional ActivityStatus activity_status = 9;
1267 | optional uint32 location_hash1 = 10; // Location1 hashed based on the auth_token - xxHash32
1268 | optional uint32 location_hash2 = 20; // Location2 hashed based on the auth_token - xxHash32
1269 | optional bytes unk22 = 22; // possibly replay check. Generation unknown but pointed to by 0001B8614
1270 | optional uint64 timestamp = 23; // epoch timestamp in ms
1271 | repeated uint64 request_hash = 24; // hashes of each request message in a hashArray - xxhash64
1272 |
1273 | // Addresses for the corresponding hash functions:
1274 | // xxHash32 00054D28
1275 | // xxhash64 000546C8 - Feeds into 00053D40
1276 |
1277 | }
1278 |
--------------------------------------------------------------------------------
/pokemons.json:
--------------------------------------------------------------------------------
1 | {
2 | "thanks": "https://github.com/Biuni/PokemonGOPokedex",
3 | "pokemon":[
4 | {
5 | "id":"1",
6 | "num":"001",
7 | "name":"Bulbasaur",
8 | "img":"http://www.serebii.net/pokemongo/pokemon/001.png",
9 | "type": "Grass / Poison",
10 | "height": "0.71 m",
11 | "weight": "6.9 kg",
12 | "candy": "25 Bulbasaur Candy",
13 | "egg": "2 km"
14 | },
15 | {
16 | "id":"2",
17 | "num":"002",
18 | "name":"Ivysaur",
19 | "img":"http://www.serebii.net/pokemongo/pokemon/002.png",
20 | "type": "Grass / Poison",
21 | "height": "0.99 m",
22 | "weight": "13.0 kg",
23 | "candy": "100 Bulbasaur Candy",
24 | "egg": "Not in Eggs"
25 | },
26 | {
27 | "id":"3",
28 | "num":"003",
29 | "name":"Venusaur",
30 | "img":"http://www.serebii.net/pokemongo/pokemon/003.png",
31 | "type": "Grass / Poison",
32 | "height": "2.01 m",
33 | "weight": "100.0 kg",
34 | "candy": "None",
35 | "egg": "Not in Eggs"
36 | },
37 | {
38 | "id":"4",
39 | "num":"004",
40 | "name":"Charmander",
41 | "img":"http://www.serebii.net/pokemongo/pokemon/004.png",
42 | "type": "Fire",
43 | "height": "0.61 m",
44 | "weight": "8.5 kg",
45 | "candy": "25 Charmander Candy",
46 | "egg": "2 km"
47 | },
48 | {
49 | "id":"5",
50 | "num":"005",
51 | "name":"Charmeleon",
52 | "img":"http://www.serebii.net/pokemongo/pokemon/005.png",
53 | "type": "Fire",
54 | "height": "1.09 m",
55 | "weight": "19.0 kg",
56 | "candy": "100 Charmander Candy",
57 | "egg": "Not in Eggs"
58 | },
59 | {
60 | "id":"6",
61 | "num":"006",
62 | "name":"Charizard",
63 | "img":"http://www.serebii.net/pokemongo/pokemon/006.png",
64 | "type": "Fire / Flying",
65 | "height": "1.70 m",
66 | "weight": "90.5 kg",
67 | "candy": "None",
68 | "egg": "Not in Eggs"
69 | },
70 | {
71 | "id":"7",
72 | "num":"007",
73 | "name":"Squirtle",
74 | "img":"http://www.serebii.net/pokemongo/pokemon/007.png",
75 | "type": "Water",
76 | "height": "0.51 m",
77 | "weight": "9.0 kg",
78 | "candy": "25 Squirtle Candy",
79 | "egg": "2 km"
80 | },
81 | {
82 | "id":"8",
83 | "num":"008",
84 | "name":"Wartortle",
85 | "img":"http://www.serebii.net/pokemongo/pokemon/008.png",
86 | "type": "Water",
87 | "height": "0.99 m",
88 | "weight": "22.5 kg",
89 | "candy": "100 Squirtle Candy",
90 | "egg": "Not in Eggs"
91 | },
92 | {
93 | "id":"9",
94 | "num":"009",
95 | "name":"Blastoise",
96 | "img":"http://www.serebii.net/pokemongo/pokemon/009.png",
97 | "type": "Water",
98 | "height": "1.60 m",
99 | "weight": "85.5 kg",
100 | "candy": "None",
101 | "egg": "Not in Eggs"
102 | },
103 | {
104 | "id":"10",
105 | "num":"010",
106 | "name":"Caterpie",
107 | "img":"http://www.serebii.net/pokemongo/pokemon/010.png",
108 | "type": "Bug",
109 | "height": "0.30 m",
110 | "weight": "2.9 kg",
111 | "candy": "12 Caterpie Candy",
112 | "egg": "2 km"
113 | },
114 | {
115 | "id":"11",
116 | "num":"011",
117 | "name":"Metapod",
118 | "img":"http://www.serebii.net/pokemongo/pokemon/011.png",
119 | "type": "Bug",
120 | "height": "0.71 m",
121 | "weight": "9.9 kg",
122 | "candy": "50 Caterpie Candy",
123 | "egg": "Not in Eggs"
124 | },
125 | {
126 | "id":"12",
127 | "num":"012",
128 | "name":"Butterfree",
129 | "img":"http://www.serebii.net/pokemongo/pokemon/012.png",
130 | "type": "Bug / Flying",
131 | "height": "1.09 m",
132 | "weight": "32.0 kg",
133 | "candy": "None",
134 | "egg": "Not in Eggs"
135 | },
136 | {
137 | "id":"13",
138 | "num":"013",
139 | "name":"Weedle",
140 | "img":"http://www.serebii.net/pokemongo/pokemon/013.png",
141 | "type": "Bug / Poison",
142 | "height": "0.30 m",
143 | "weight": "3.2 kg",
144 | "candy": "12 Weedle Candy",
145 | "egg": "2 km"
146 | },
147 | {
148 | "id":"14",
149 | "num":"014",
150 | "name":"Kakuna",
151 | "img":"http://www.serebii.net/pokemongo/pokemon/014.png",
152 | "type": "Bug / Poison",
153 | "height": "0.61 m",
154 | "weight": "10.0 kg",
155 | "candy": "50 Weedle Candy",
156 | "egg": "Not in Eggs"
157 | },
158 | {
159 | "id":"15",
160 | "num":"015",
161 | "name":"Beedrill",
162 | "img":"http://www.serebii.net/pokemongo/pokemon/015.png",
163 | "type": "Bug / Poison",
164 | "height": "0.99 m",
165 | "weight": "29.5 kg",
166 | "candy": "None",
167 | "egg": "Not in Eggs"
168 | },
169 | {
170 | "id":"16",
171 | "num":"016",
172 | "name":"Pidgey",
173 | "img":"http://www.serebii.net/pokemongo/pokemon/016.png",
174 | "type": "Normal / Flying",
175 | "height": "0.30 m",
176 | "weight": "1.8 kg",
177 | "candy": "12 Pidgey Candy",
178 | "egg": "2 km"
179 | },
180 | {
181 | "id":"17",
182 | "num":"017",
183 | "name":"Pidgeotto",
184 | "img":"http://www.serebii.net/pokemongo/pokemon/017.png",
185 | "type": "Normal / Flying",
186 | "height": "1.09 m",
187 | "weight": "30.0 kg",
188 | "candy": "50 Pidgey Candy",
189 | "egg": "Not in Eggs"
190 | },
191 | {
192 | "id":"18",
193 | "num":"018",
194 | "name":"Pidgeot",
195 | "img":"http://www.serebii.net/pokemongo/pokemon/018.png",
196 | "type": "Normal / Flying",
197 | "height": "1.50 m",
198 | "weight": "39.5 kg",
199 | "candy": "None",
200 | "egg": "Not in Eggs"
201 | },
202 | {
203 | "id":"19",
204 | "num":"019",
205 | "name":"Rattata",
206 | "img":"http://www.serebii.net/pokemongo/pokemon/019.png",
207 | "type": "Normal",
208 | "height": "0.30 m",
209 | "weight": "3.5 kg",
210 | "candy": "25 Rattata Candy",
211 | "egg": "2 km"
212 | },
213 | {
214 | "id":"20",
215 | "num":"020",
216 | "name":"Raticate",
217 | "img":"http://www.serebii.net/pokemongo/pokemon/020.png",
218 | "type": "Normal",
219 | "height": "0.71 m",
220 | "weight": "18.5 kg",
221 | "candy": "None",
222 | "egg": "Not in Eggs"
223 | },
224 | {
225 | "id":"21",
226 | "num":"021",
227 | "name":"Spearow",
228 | "img":"http://www.serebii.net/pokemongo/pokemon/021.png",
229 | "type": "Normal / Flying",
230 | "height": "0.30 m",
231 | "weight": "2.0 kg",
232 | "candy": "50 Spearow Candy",
233 | "egg": "2 km"
234 | },
235 | {
236 | "id":"22",
237 | "num":"022",
238 | "name":"Fearow",
239 | "img":"http://www.serebii.net/pokemongo/pokemon/022.png",
240 | "type": "Normal / Flying",
241 | "height": "1.19 m",
242 | "weight": "38.0 kg",
243 | "candy": "None",
244 | "egg": "Not in Eggs"
245 | },
246 | {
247 | "id":"23",
248 | "num":"023",
249 | "name":"Ekans",
250 | "img":"http://www.serebii.net/pokemongo/pokemon/023.png",
251 | "type": "Poison",
252 | "height": "2.01 m",
253 | "weight": "6.9 kg",
254 | "candy": "50 Ekans Candy",
255 | "egg": "5 km"
256 | },
257 | {
258 | "id":"24",
259 | "num":"024",
260 | "name":"Arbok",
261 | "img":"http://www.serebii.net/pokemongo/pokemon/024.png",
262 | "type": "Poison",
263 | "height": "3.51 m",
264 | "weight": "65.0 kg",
265 | "candy": "None",
266 | "egg": "Not in Eggs"
267 | },
268 | {
269 | "id":"25",
270 | "num":"025",
271 | "name":"Pikachu",
272 | "img":"http://www.serebii.net/pokemongo/pokemon/025.png",
273 | "type": "Electric",
274 | "height": "0.41 m",
275 | "weight": "6.0 kg",
276 | "candy": "50 Pikachu Candy",
277 | "egg": "2 km"
278 | },
279 | {
280 | "id":"26",
281 | "num":"026",
282 | "name":"Raichu",
283 | "img":"http://www.serebii.net/pokemongo/pokemon/026.png",
284 | "type": "Electric",
285 | "height": "0.79 m",
286 | "weight": "30.0 kg",
287 | "candy": "None",
288 | "egg": "Not in Eggs"
289 | },
290 | {
291 | "id":"27",
292 | "num":"027",
293 | "name":"Sandshrew",
294 | "img":"http://www.serebii.net/pokemongo/pokemon/027.png",
295 | "type": "Ground",
296 | "height": "0.61 m",
297 | "weight": "12.0 kg",
298 | "candy": "50 Sandshrew Candy",
299 | "egg": "5 km"
300 | },
301 | {
302 | "id":"28",
303 | "num":"028",
304 | "name":"Sandslash",
305 | "img":"http://www.serebii.net/pokemongo/pokemon/028.png",
306 | "type": "Ground",
307 | "height": "0.99 m",
308 | "weight": "29.5 kg",
309 | "candy": "None",
310 | "egg": "Not in Eggs"
311 | },
312 | {
313 | "id":"29",
314 | "num":"029",
315 | "name":"Nidoran ♀",
316 | "img":"http://www.serebii.net/pokemongo/pokemon/029.png",
317 | "type": "Poison",
318 | "height": "0.41 m",
319 | "weight": "7.0 kg",
320 | "candy": "25 Nidoran ♀ Candy",
321 | "egg": "5 km"
322 | },
323 | {
324 | "id":"30",
325 | "num":"030",
326 | "name":"Nidorina",
327 | "img":"http://www.serebii.net/pokemongo/pokemon/030.png",
328 | "type": "Poison",
329 | "height": "0.79 m",
330 | "weight": "20.0 kg",
331 | "candy": "100 Nidoran ♀ Candy",
332 | "egg": "Not in Eggs"
333 | },
334 | {
335 | "id":"31",
336 | "num":"031",
337 | "name":"Nidoqueen",
338 | "img":"http://www.serebii.net/pokemongo/pokemon/031.png",
339 | "type": "Poison / Ground",
340 | "height": "1.30 m",
341 | "weight": "60.0 kg",
342 | "candy": "None",
343 | "egg": "Not in Eggs"
344 | },
345 | {
346 | "id":"32",
347 | "num":"032",
348 | "name":"Nidoran ♂",
349 | "img":"http://www.serebii.net/pokemongo/pokemon/032.png",
350 | "type": "Poison",
351 | "height": "0.51 m",
352 | "weight": "9.0 kg",
353 | "candy": "25 Nidoran♂ Candy",
354 | "egg": "5 km"
355 | },
356 | {
357 | "id":"33",
358 | "num":"033",
359 | "name":"Nidorino",
360 | "img":"http://www.serebii.net/pokemongo/pokemon/033.png",
361 | "type": "Poison",
362 | "height": "0.89 m",
363 | "weight": "19.5 kg",
364 | "candy": "100 Nidoran ♂ Candy",
365 | "egg": "Not in Eggs"
366 | },
367 | {
368 | "id":"34",
369 | "num":"034",
370 | "name":"Nidoking",
371 | "img":"http://www.serebii.net/pokemongo/pokemon/034.png",
372 | "type": "Poison / Ground",
373 | "height": "1.40 m",
374 | "weight": "62.0 kg",
375 | "candy": "None",
376 | "egg": "Not in Eggs"
377 | },
378 | {
379 | "id":"35",
380 | "num":"035",
381 | "name":"Clefairy",
382 | "img":"http://www.serebii.net/pokemongo/pokemon/035.png",
383 | "type": "Normal",
384 | "height": "0.61 m",
385 | "weight": "7.5 kg",
386 | "candy": "50 Clefairy Candy",
387 | "egg": "2 km"
388 | },
389 | {
390 | "id":"36",
391 | "num":"036",
392 | "name":"Clefable",
393 | "img":"http://www.serebii.net/pokemongo/pokemon/036.png",
394 | "type": "Normal",
395 | "height": "1.30 m",
396 | "weight": "40.0 kg",
397 | "candy": "None",
398 | "egg": "Not in Eggs"
399 | },
400 | {
401 | "id":"37",
402 | "num":"037",
403 | "name":"Vulpix",
404 | "img":"http://www.serebii.net/pokemongo/pokemon/037.png",
405 | "type": "Fire",
406 | "height": "0.61 m",
407 | "weight": "9.9 kg",
408 | "candy": "50 Vulpix Candy",
409 | "egg": "5 km"
410 | },
411 | {
412 | "id":"38",
413 | "num":"038",
414 | "name":"Ninetales",
415 | "img":"http://www.serebii.net/pokemongo/pokemon/038.png",
416 | "type": "Fire",
417 | "height": "1.09 m",
418 | "weight": "19.9 kg",
419 | "candy": "None",
420 | "egg": "Not in Eggs"
421 | },
422 | {
423 | "id":"39",
424 | "num":"039",
425 | "name":"Jigglypuff",
426 | "img":"http://www.serebii.net/pokemongo/pokemon/039.png",
427 | "type": "Normal",
428 | "height": "0.51 m",
429 | "weight": "5.5 kg",
430 | "candy": "50 Jigglypuff Candy",
431 | "egg": "2 km"
432 | },
433 | {
434 | "id":"40",
435 | "num":"040",
436 | "name":"Wigglytuff",
437 | "img":"http://www.serebii.net/pokemongo/pokemon/040.png",
438 | "type": "Normal",
439 | "height": "0.99 m",
440 | "weight": "12.0 kg",
441 | "candy": "None",
442 | "egg": "Not in Eggs"
443 | },
444 | {
445 | "id":"41",
446 | "num":"041",
447 | "name":"Zubat",
448 | "img":"http://www.serebii.net/pokemongo/pokemon/041.png",
449 | "type": "Poison / Flying",
450 | "height": "0.79 m",
451 | "weight": "7.5 kg",
452 | "candy": "50 Zubat Candy",
453 | "egg": "2 km"
454 | },
455 | {
456 | "id":"42",
457 | "num":"042",
458 | "name":"Golbat",
459 | "img":"http://www.serebii.net/pokemongo/pokemon/042.png",
460 | "type": "Poison / Flying",
461 | "height": "1.60 m",
462 | "weight": "55.0 kg",
463 | "candy": "None",
464 | "egg": "Not in Eggs"
465 | },
466 | {
467 | "id":"43",
468 | "num":"043",
469 | "name":"Oddish",
470 | "img":"http://www.serebii.net/pokemongo/pokemon/043.png",
471 | "type": "Grass / Poison",
472 | "height": "0.51 m",
473 | "weight": "5.4 kg",
474 | "candy": "25 Oddish Candy",
475 | "egg": "5 km"
476 | },
477 | {
478 | "id":"44",
479 | "num":"044",
480 | "name":"Gloom",
481 | "img":"http://www.serebii.net/pokemongo/pokemon/044.png",
482 | "type": "Grass / Poison",
483 | "height": "0.79 m",
484 | "weight": "8.6 kg",
485 | "candy": "100 Oddish Candy",
486 | "egg": "Not in Eggs"
487 | },
488 | {
489 | "id":"45",
490 | "num":"045",
491 | "name":"Vileplume",
492 | "img":"http://www.serebii.net/pokemongo/pokemon/045.png",
493 | "type": "Grass / Poison",
494 | "height": "1.19 m",
495 | "weight": "18.6 kg",
496 | "candy": "None",
497 | "egg": "Not in Eggs"
498 | },
499 | {
500 | "id":"46",
501 | "num":"046",
502 | "name":"Paras",
503 | "img":"http://www.serebii.net/pokemongo/pokemon/046.png",
504 | "type": "Bug / Grass",
505 | "height": "0.30 m",
506 | "weight": "5.4 kg",
507 | "candy": "50 Paras Candy",
508 | "egg": "5 km"
509 | },
510 | {
511 | "id":"47",
512 | "num":"047",
513 | "name":"Parasect",
514 | "img":"http://www.serebii.net/pokemongo/pokemon/047.png",
515 | "type": "Bug / Grass",
516 | "height": "0.99 m",
517 | "weight": "29.5 kg",
518 | "candy": "None",
519 | "egg": "Not in Eggs"
520 | },
521 | {
522 | "id":"48",
523 | "num":"048",
524 | "name":"Venonat",
525 | "img":"http://www.serebii.net/pokemongo/pokemon/048.png",
526 | "type": "Bug / Poison",
527 | "height": "0.99 m",
528 | "weight": "30.0 kg",
529 | "candy": "50 Venonat Candy",
530 | "egg": "5 km"
531 | },
532 | {
533 | "id":"49",
534 | "num":"049",
535 | "name":"Venomoth",
536 | "img":"http://www.serebii.net/pokemongo/pokemon/049.png",
537 | "type": "Bug / Poison",
538 | "height": "1.50 m",
539 | "weight": "12.5 kg",
540 | "candy": "None",
541 | "egg": "Not in Eggs"
542 | },
543 | {
544 | "id":"50",
545 | "num":"050",
546 | "name":"Diglett",
547 | "img":"http://www.serebii.net/pokemongo/pokemon/050.png",
548 | "type": "Ground",
549 | "height": "0.20 m",
550 | "weight": "0.8 kg",
551 | "candy": "50 Diglett Candy",
552 | "egg": "5 km"
553 | },
554 | {
555 | "id":"51",
556 | "num":"051",
557 | "name":"Dugtrio",
558 | "img":"http://www.serebii.net/pokemongo/pokemon/051.png",
559 | "type": "Ground",
560 | "height": "0.71 m",
561 | "weight": "33.3 kg",
562 | "candy": "None",
563 | "egg": "Not in Eggs"
564 | },
565 | {
566 | "id":"52",
567 | "num":"052",
568 | "name":"Meowth",
569 | "img":"http://www.serebii.net/pokemongo/pokemon/052.png",
570 | "type": "Normal",
571 | "height": "0.41 m",
572 | "weight": "4.2 kg",
573 | "candy": "50 Meowth Candy",
574 | "egg": "5 km"
575 | },
576 | {
577 | "id":"53",
578 | "num":"053",
579 | "name":"Persian",
580 | "img":"http://www.serebii.net/pokemongo/pokemon/053.png",
581 | "type": "Normal",
582 | "height": "0.99 m",
583 | "weight": "32.0 kg",
584 | "candy": "None",
585 | "egg": "Not in Eggs"
586 | },
587 | {
588 | "id":"54",
589 | "num":"054",
590 | "name":"Psyduck",
591 | "img":"http://www.serebii.net/pokemongo/pokemon/054.png",
592 | "type": "Water",
593 | "height": "0.79 m",
594 | "weight": "19.6 kg",
595 | "candy": "50 Psyduck Candy",
596 | "egg": "5 km"
597 | },
598 | {
599 | "id":"55",
600 | "num":"055",
601 | "name":"Golduck",
602 | "img":"http://www.serebii.net/pokemongo/pokemon/055.png",
603 | "type": "Water",
604 | "height": "1.70 m",
605 | "weight": "76.6 kg",
606 | "candy": "None",
607 | "egg": "Not in Eggs"
608 | },
609 | {
610 | "id":"56",
611 | "num":"056",
612 | "name":"Mankey",
613 | "img":"http://www.serebii.net/pokemongo/pokemon/056.png",
614 | "type": "Fighting",
615 | "height": "0.51 m",
616 | "weight": "28.0 kg",
617 | "candy": "50 Mankey Candy",
618 | "egg": "5 km"
619 | },
620 | {
621 | "id":"57",
622 | "num":"057",
623 | "name":"Primeape",
624 | "img":"http://www.serebii.net/pokemongo/pokemon/057.png",
625 | "type": "Fighting",
626 | "height": "0.99 m",
627 | "weight": "32.0 kg",
628 | "candy": "None",
629 | "egg": "Not in Eggs"
630 | },
631 | {
632 | "id":"58",
633 | "num":"058",
634 | "name":"Growlithe",
635 | "img":"http://www.serebii.net/pokemongo/pokemon/058.png",
636 | "type": "Fire",
637 | "height": "0.71 m",
638 | "weight": "19.0 kg",
639 | "candy": "50 Growlithe Candy",
640 | "egg": "5 km"
641 | },
642 | {
643 | "id":"59",
644 | "num":"059",
645 | "name":"Arcanine",
646 | "img":"http://www.serebii.net/pokemongo/pokemon/059.png",
647 | "type": "Fire",
648 | "height": "1.91 m",
649 | "weight": "155.0 kg",
650 | "candy": "None",
651 | "egg": "Not in Eggs"
652 | },
653 | {
654 | "id":"60",
655 | "num":"060",
656 | "name":"Poliwag",
657 | "img":"http://www.serebii.net/pokemongo/pokemon/060.png",
658 | "type": "Water",
659 | "height": "0.61 m",
660 | "weight": "12.4 kg",
661 | "candy": "25 Poliwag Candy",
662 | "egg": "5 km"
663 | },
664 | {
665 | "id":"61",
666 | "num":"061",
667 | "name":"Poliwhirl",
668 | "img":"http://www.serebii.net/pokemongo/pokemon/061.png",
669 | "type": "Water",
670 | "height": "0.99 m",
671 | "weight": "20.0 kg",
672 | "candy": "100 Poliwag Candy",
673 | "egg": "Not in Eggs"
674 | },
675 | {
676 | "id":"62",
677 | "num":"062",
678 | "name":"Poliwrath",
679 | "img":"http://www.serebii.net/pokemongo/pokemon/062.png",
680 | "type": "Water / Fighting",
681 | "height": "1.30 m",
682 | "weight": "54.0 kg",
683 | "candy": "None",
684 | "egg": "Not in Eggs"
685 | },
686 | {
687 | "id":"63",
688 | "num":"063",
689 | "name":"Abra",
690 | "img":"http://www.serebii.net/pokemongo/pokemon/063.png",
691 | "type": "Psychic",
692 | "height": "0.89 m",
693 | "weight": "19.5 kg",
694 | "candy": "25 Abra Candy",
695 | "egg": "5 km"
696 | },
697 | {
698 | "id":"64",
699 | "num":"064",
700 | "name":"Kadabra",
701 | "img":"http://www.serebii.net/pokemongo/pokemon/064.png",
702 | "type": "Psychic",
703 | "height": "1.30 m",
704 | "weight": "56.5 kg",
705 | "candy": "100 Abra Candy",
706 | "egg": "Not in Eggs"
707 | },
708 | {
709 | "id":"65",
710 | "num":"065",
711 | "name":"Alakazam",
712 | "img":"http://www.serebii.net/pokemongo/pokemon/065.png",
713 | "type": "Psychic",
714 | "height": "1.50 m",
715 | "weight": "48.0 kg",
716 | "candy": "None",
717 | "egg": "Not in Eggs"
718 | },
719 | {
720 | "id":"66",
721 | "num":"066",
722 | "name":"Machop",
723 | "img":"http://www.serebii.net/pokemongo/pokemon/066.png",
724 | "type": "Fighting",
725 | "height": "0.79 m",
726 | "weight": "19.5 kg",
727 | "candy": "25 Machop Candy",
728 | "egg": "5 km"
729 | },
730 | {
731 | "id":"67",
732 | "num":"067",
733 | "name":"Machoke",
734 | "img":"http://www.serebii.net/pokemongo/pokemon/067.png",
735 | "type": "Fighting",
736 | "height": "1.50 m",
737 | "weight": "70.5 kg",
738 | "candy": "100 Machop Candy",
739 | "egg": "Not in Eggs"
740 | },
741 | {
742 | "id":"68",
743 | "num":"068",
744 | "name":"Machamp",
745 | "img":"http://www.serebii.net/pokemongo/pokemon/068.png",
746 | "type": "Fighting",
747 | "height": "1.60 m",
748 | "weight": "130.0 kg",
749 | "candy": "None",
750 | "egg": "Not in Eggs"
751 | },
752 | {
753 | "id":"69",
754 | "num":"069",
755 | "name":"Bellsprout",
756 | "img":"http://www.serebii.net/pokemongo/pokemon/069.png",
757 | "type": "Grass / Poison",
758 | "height": "0.71 m",
759 | "weight": "4.0 kg",
760 | "candy": "25 Bellsprout Candy",
761 | "egg": "5 km"
762 | },
763 | {
764 | "id":"70",
765 | "num":"070",
766 | "name":"Weepinbell",
767 | "img":"http://www.serebii.net/pokemongo/pokemon/070.png",
768 | "type": "Grass / Poison",
769 | "height": "0.99 m",
770 | "weight": "6.4 kg",
771 | "candy": "100 Bellsprout Candy",
772 | "egg": "Not in Eggs"
773 | },
774 | {
775 | "id":"71",
776 | "num":"071",
777 | "name":"Victreebel",
778 | "img":"http://www.serebii.net/pokemongo/pokemon/071.png",
779 | "type": "Grass / Poison",
780 | "height": "1.70 m",
781 | "weight": "15.5 kg",
782 | "candy": "None",
783 | "egg": "Not in Eggs"
784 | },
785 | {
786 | "id":"72",
787 | "num":"072",
788 | "name":"Tentacool",
789 | "img":"http://www.serebii.net/pokemongo/pokemon/072.png",
790 | "type": "Water / Poison",
791 | "height": "0.89 m",
792 | "weight": "45.5 kg",
793 | "candy": "50 Tentacool Candy",
794 | "egg": "5 km"
795 | },
796 | {
797 | "id":"73",
798 | "num":"073",
799 | "name":"Tentacruel",
800 | "img":"http://www.serebii.net/pokemongo/pokemon/073.png",
801 | "type": "Water / Poison",
802 | "height": "1.60 m",
803 | "weight": "55.0 kg",
804 | "candy": "None",
805 | "egg": "Not in Eggs"
806 | },
807 | {
808 | "id":"74",
809 | "num":"074",
810 | "name":"Geodude",
811 | "img":"http://www.serebii.net/pokemongo/pokemon/074.png",
812 | "type": "Rock / Ground",
813 | "height": "0.41 m",
814 | "weight": "20.0 kg",
815 | "candy": "25 Geodude Candy",
816 | "egg": "2 km"
817 | },
818 | {
819 | "id":"75",
820 | "num":"075",
821 | "name":"Graveler",
822 | "img":"http://www.serebii.net/pokemongo/pokemon/075.png",
823 | "type": "Rock / Ground",
824 | "height": "0.99 m",
825 | "weight": "105.0 kg",
826 | "candy": "100 Geodude Candy",
827 | "egg": "Not in Eggs"
828 | },
829 | {
830 | "id":"76",
831 | "num":"076",
832 | "name":"Golem",
833 | "img":"http://www.serebii.net/pokemongo/pokemon/076.png",
834 | "type": "Rock / Ground",
835 | "height": "1.40 m",
836 | "weight": "300.0 kg",
837 | "candy": "None",
838 | "egg": "Not in Eggs"
839 | },
840 | {
841 | "id":"77",
842 | "num":"077",
843 | "name":"Ponyta",
844 | "img":"http://www.serebii.net/pokemongo/pokemon/077.png",
845 | "type": "Fire",
846 | "height": "0.99 m",
847 | "weight": "30.0 kg",
848 | "candy": "50 Ponyta Candy",
849 | "egg": "5 km"
850 | },
851 | {
852 | "id":"78",
853 | "num":"078",
854 | "name":"Rapidash",
855 | "img":"http://www.serebii.net/pokemongo/pokemon/078.png",
856 | "type": "Fire",
857 | "height": "1.70 m",
858 | "weight": "95.0 kg",
859 | "candy": "None",
860 | "egg": "Not in Eggs"
861 | },
862 | {
863 | "id":"79",
864 | "num":"079",
865 | "name":"Slowpoke",
866 | "img":"http://www.serebii.net/pokemongo/pokemon/079.png",
867 | "type": "Water / Psychic",
868 | "height": "1.19 m",
869 | "weight": "36.0 kg",
870 | "candy": "50 Slowpoke Candy",
871 | "egg": "5 km"
872 | },
873 | {
874 | "id":"80",
875 | "num":"080",
876 | "name":"Slowbro",
877 | "img":"http://www.serebii.net/pokemongo/pokemon/080.png",
878 | "type": "Water / Psychic",
879 | "height": "1.60 m",
880 | "weight": "78.5 kg",
881 | "candy": "None",
882 | "egg": "Not in Eggs"
883 | },
884 | {
885 | "id":"81",
886 | "num":"081",
887 | "name":"Magnemite",
888 | "img":"http://www.serebii.net/pokemongo/pokemon/081.png",
889 | "type": "Electric",
890 | "height": "0.30 m",
891 | "weight": "6.0 kg",
892 | "candy": "50 Magnemite Candy",
893 | "egg": "5 km"
894 | },
895 | {
896 | "id":"82",
897 | "num":"082",
898 | "name":"Magneton",
899 | "img":"http://www.serebii.net/pokemongo/pokemon/082.png",
900 | "type": "Electric",
901 | "height": "0.99 m",
902 | "weight": "60.0 kg",
903 | "candy": "None",
904 | "egg": "Not in Eggs"
905 | },
906 | {
907 | "id":"83",
908 | "num":"083",
909 | "name":"Farfetch'd",
910 | "img":"http://www.serebii.net/pokemongo/pokemon/083.png",
911 | "type": "Normal / Flying",
912 | "height": "0.79 m",
913 | "weight": "15.0 kg",
914 | "candy": "None",
915 | "egg": "5 km"
916 | },
917 | {
918 | "id":"84",
919 | "num":"084",
920 | "name":"Doduo",
921 | "img":"http://www.serebii.net/pokemongo/pokemon/084.png",
922 | "type": "Normal / Flying",
923 | "height": "1.40 m",
924 | "weight": "39.2 kg",
925 | "candy": "50 Doduo Candy",
926 | "egg": "5 km"
927 | },
928 | {
929 | "id":"85",
930 | "num":"085",
931 | "name":"Dodrio",
932 | "img":"http://www.serebii.net/pokemongo/pokemon/085.png",
933 | "type": "Normal / Flying",
934 | "height": "1.80 m",
935 | "weight": "85.2 kg",
936 | "candy": "None",
937 | "egg": "Not in Eggs"
938 | },
939 | {
940 | "id":"86",
941 | "num":"086",
942 | "name":"Seel",
943 | "img":"http://www.serebii.net/pokemongo/pokemon/086.png",
944 | "type": "Water",
945 | "height": "1.09 m",
946 | "weight": "90.0 kg",
947 | "candy": "50 Seel Candy",
948 | "egg": "5 km"
949 | },
950 | {
951 | "id":"87",
952 | "num":"087",
953 | "name":"Dewgong",
954 | "img":"http://www.serebii.net/pokemongo/pokemon/087.png",
955 | "type": "Water / Ice",
956 | "height": "1.70 m",
957 | "weight": "120.0 kg",
958 | "candy": "None",
959 | "egg": "Not in Eggs"
960 | },
961 | {
962 | "id":"88",
963 | "num":"088",
964 | "name":"Grimer",
965 | "img":"http://www.serebii.net/pokemongo/pokemon/088.png",
966 | "type": "Poison",
967 | "height": "0.89 m",
968 | "weight": "30.0 kg",
969 | "candy": "50 Grimer Candy",
970 | "egg": "5 km"
971 | },
972 | {
973 | "id":"89",
974 | "num":"089",
975 | "name":"Muk",
976 | "img":"http://www.serebii.net/pokemongo/pokemon/089.png",
977 | "type": "Poison",
978 | "height": "1.19 m",
979 | "weight": "30.0 kg",
980 | "candy": "None",
981 | "egg": "Not in Eggs"
982 | },
983 | {
984 | "id":"90",
985 | "num":"090",
986 | "name":"Shellder",
987 | "img":"http://www.serebii.net/pokemongo/pokemon/090.png",
988 | "type": "Water",
989 | "height": "0.30 m",
990 | "weight": "4.0 kg",
991 | "candy": "50 Shellder Candy",
992 | "egg": "5 km"
993 | },
994 | {
995 | "id":"91",
996 | "num":"091",
997 | "name":"Cloyster",
998 | "img":"http://www.serebii.net/pokemongo/pokemon/091.png",
999 | "type": "Water / Ice",
1000 | "height": "1.50 m",
1001 | "weight": "132.5 kg",
1002 | "candy": "None",
1003 | "egg": "Not in Eggs"
1004 | },
1005 | {
1006 | "id":"92",
1007 | "num":"092",
1008 | "name":"Gastly",
1009 | "img":"http://www.serebii.net/pokemongo/pokemon/092.png",
1010 | "type": "Ghost / Poison",
1011 | "height": "1.30 m",
1012 | "weight": "0.1 kg",
1013 | "candy": "25 Gastly Candy",
1014 | "egg": "5 km"
1015 | },
1016 | {
1017 | "id":"93",
1018 | "num":"093",
1019 | "name":"Haunter",
1020 | "img":"http://www.serebii.net/pokemongo/pokemon/093.png",
1021 | "type": "Ghost / Poison",
1022 | "height": "1.60 m",
1023 | "weight": "0.1 kg",
1024 | "candy": "100 Gastly Candy",
1025 | "egg": "Not in Eggs"
1026 | },
1027 | {
1028 | "id":"94",
1029 | "num":"094",
1030 | "name":"Gengar",
1031 | "img":"http://www.serebii.net/pokemongo/pokemon/094.png",
1032 | "type": "Ghost / Poison",
1033 | "height": "1.50 m",
1034 | "weight": "40.5 kg",
1035 | "candy": "None",
1036 | "egg": "Not in Eggs"
1037 | },
1038 | {
1039 | "id":"95",
1040 | "num":"095",
1041 | "name":"Onix",
1042 | "img":"http://www.serebii.net/pokemongo/pokemon/095.png",
1043 | "type": "Rock / Ground",
1044 | "height": "8.79 m",
1045 | "weight": "210.0 kg",
1046 | "candy": "None",
1047 | "egg": "10 km"
1048 | },
1049 | {
1050 | "id":"96",
1051 | "num":"096",
1052 | "name":"Drowzee",
1053 | "img":"http://www.serebii.net/pokemongo/pokemon/096.png",
1054 | "type": "Psychic",
1055 | "height": "0.99 m",
1056 | "weight": "32.4 kg",
1057 | "candy": "50 Drowzee Candy",
1058 | "egg": "5 km"
1059 | },
1060 | {
1061 | "id":"97",
1062 | "num":"097",
1063 | "name":"Hypno",
1064 | "img":"http://www.serebii.net/pokemongo/pokemon/097.png",
1065 | "type": "Psychic",
1066 | "height": "1.60 m",
1067 | "weight": "75.6 kg",
1068 | "candy": "None",
1069 | "egg": "Not in Eggs"
1070 | },
1071 | {
1072 | "id":"98",
1073 | "num":"098",
1074 | "name":"Krabby",
1075 | "img":"http://www.serebii.net/pokemongo/pokemon/098.png",
1076 | "type": "Water",
1077 | "height": "0.41 m",
1078 | "weight": "6.5 kg",
1079 | "candy": "50 Krabby Candy",
1080 | "egg": "5 km"
1081 | },
1082 | {
1083 | "id":"99",
1084 | "num":"099",
1085 | "name":"Kingler",
1086 | "img":"http://www.serebii.net/pokemongo/pokemon/099.png",
1087 | "type": "Water",
1088 | "height": "1.30 m",
1089 | "weight": "60.0 kg",
1090 | "candy": "None",
1091 | "egg": "Not in Eggs"
1092 | },
1093 | {
1094 | "id":"100",
1095 | "num":"100",
1096 | "name":"Voltorb",
1097 | "img":"http://www.serebii.net/pokemongo/pokemon/100.png",
1098 | "type": "Electric",
1099 | "height": "0.51 m",
1100 | "weight": "10.4 kg",
1101 | "candy": "50 Voltorb Candy",
1102 | "egg": "5 km"
1103 | },
1104 | {
1105 | "id":"101",
1106 | "num":"101",
1107 | "name":"Electrode",
1108 | "img":"http://www.serebii.net/pokemongo/pokemon/101.png",
1109 | "type": "Electric",
1110 | "height": "1.19 m",
1111 | "weight": "66.6 kg",
1112 | "candy": "None",
1113 | "egg": "Not in Eggs"
1114 | },
1115 | {
1116 | "id":"102",
1117 | "num":"102",
1118 | "name":"Exeggcute",
1119 | "img":"http://www.serebii.net/pokemongo/pokemon/102.png",
1120 | "type": "Grass / Psychic",
1121 | "height": "0.41 m",
1122 | "weight": "2.5 kg",
1123 | "candy": "50 Exeggcute Candy",
1124 | "egg": "5 km"
1125 | },
1126 | {
1127 | "id":"103",
1128 | "num":"103",
1129 | "name":"Exeggutor",
1130 | "img":"http://www.serebii.net/pokemongo/pokemon/103.png",
1131 | "type": "Grass / Psychic",
1132 | "height": "2.01 m",
1133 | "weight": "120.0 kg",
1134 | "candy": "None",
1135 | "egg": "Not in Eggs"
1136 | },
1137 | {
1138 | "id":"104",
1139 | "num":"104",
1140 | "name":"Cubone",
1141 | "img":"http://www.serebii.net/pokemongo/pokemon/104.png",
1142 | "type": "Ground",
1143 | "height": "0.41 m",
1144 | "weight": "6.5 kg",
1145 | "candy": "50 Cubone Candy",
1146 | "egg": "5 km"
1147 | },
1148 | {
1149 | "id":"105",
1150 | "num":"105",
1151 | "name":"Marowak",
1152 | "img":"http://www.serebii.net/pokemongo/pokemon/105.png",
1153 | "type": "Ground",
1154 | "height": "0.99 m",
1155 | "weight": "45.0 kg",
1156 | "candy": "None",
1157 | "egg": "Not in Eggs"
1158 | },
1159 | {
1160 | "id":"106",
1161 | "num":"106",
1162 | "name":"Hitmonlee",
1163 | "img":"http://www.serebii.net/pokemongo/pokemon/106.png",
1164 | "type": "Fighting",
1165 | "height": "1.50 m",
1166 | "weight": "49.8 kg",
1167 | "candy": "None",
1168 | "egg": "10 km"
1169 | },
1170 | {
1171 | "id":"107",
1172 | "num":"107",
1173 | "name":"Hitmonchan",
1174 | "img":"http://www.serebii.net/pokemongo/pokemon/107.png",
1175 | "type": "Fighting",
1176 | "height": "1.40 m",
1177 | "weight": "50.2 kg",
1178 | "candy": "None",
1179 | "egg": "10 km"
1180 | },
1181 | {
1182 | "id":"108",
1183 | "num":"108",
1184 | "name":"Lickitung",
1185 | "img":"http://www.serebii.net/pokemongo/pokemon/108.png",
1186 | "type": "Normal",
1187 | "height": "1.19 m",
1188 | "weight": "65.5 kg",
1189 | "candy": "None",
1190 | "egg": "5 km"
1191 | },
1192 | {
1193 | "id":"109",
1194 | "num":"109",
1195 | "name":"Koffing",
1196 | "img":"http://www.serebii.net/pokemongo/pokemon/109.png",
1197 | "type": "Poison",
1198 | "height": "0.61 m",
1199 | "weight": "1.0 kg",
1200 | "candy": "50 Koffing Candy",
1201 | "egg": "5 km"
1202 | },
1203 | {
1204 | "id":"110",
1205 | "num":"110",
1206 | "name":"Weezing",
1207 | "img":"http://www.serebii.net/pokemongo/pokemon/110.png",
1208 | "type": "Poison",
1209 | "height": "1.19 m",
1210 | "weight": "9.5 kg",
1211 | "candy": "None",
1212 | "egg": "Not in Eggs"
1213 | },
1214 | {
1215 | "id":"111",
1216 | "num":"111",
1217 | "name":"Rhyhorn",
1218 | "img":"http://www.serebii.net/pokemongo/pokemon/111.png",
1219 | "type": "Ground / Rock",
1220 | "height": "0.99 m",
1221 | "weight": "115.0 kg",
1222 | "candy": "50 Rhyhorn Candy",
1223 | "egg": "5 km"
1224 | },
1225 | {
1226 | "id":"112",
1227 | "num":"112",
1228 | "name":"Rhydon",
1229 | "img":"http://www.serebii.net/pokemongo/pokemon/112.png",
1230 | "type": "Ground / Rock",
1231 | "height": "1.91 m",
1232 | "weight": "120.0 kg",
1233 | "candy": "None",
1234 | "egg": "Not in Eggs"
1235 | },
1236 | {
1237 | "id":"113",
1238 | "num":"113",
1239 | "name":"Chansey",
1240 | "img":"http://www.serebii.net/pokemongo/pokemon/113.png",
1241 | "type": "Normal",
1242 | "height": "1.09 m",
1243 | "weight": "34.6 kg",
1244 | "candy": "None",
1245 | "egg": "10 km"
1246 | },
1247 | {
1248 | "id":"114",
1249 | "num":"114",
1250 | "name":"Tangela",
1251 | "img":"http://www.serebii.net/pokemongo/pokemon/114.png",
1252 | "type": "Grass",
1253 | "height": "0.99 m",
1254 | "weight": "35.0 kg",
1255 | "candy": "None",
1256 | "egg": "5 km"
1257 | },
1258 | {
1259 | "id":"115",
1260 | "num":"115",
1261 | "name":"Kangaskhan",
1262 | "img":"http://www.serebii.net/pokemongo/pokemon/115.png",
1263 | "type": "Normal",
1264 | "height": "2.21 m",
1265 | "weight": "80.0 kg",
1266 | "candy": "None",
1267 | "egg": "5 km"
1268 | },
1269 | {
1270 | "id":"116",
1271 | "num":"116",
1272 | "name":"Horsea",
1273 | "img":"http://www.serebii.net/pokemongo/pokemon/116.png",
1274 | "type": "Water",
1275 | "height": "0.41 m",
1276 | "weight": "8.0 kg",
1277 | "candy": "50 Horsea Candy",
1278 | "egg": "5 km"
1279 | },
1280 | {
1281 | "id":"117",
1282 | "num":"117",
1283 | "name":"Seadra",
1284 | "img":"http://www.serebii.net/pokemongo/pokemon/117.png",
1285 | "type": "Water",
1286 | "height": "1.19 m",
1287 | "weight": "25.0 kg",
1288 | "candy": "None",
1289 | "egg": "Not in Eggs"
1290 | },
1291 | {
1292 | "id":"118",
1293 | "num":"118",
1294 | "name":"Goldeen",
1295 | "img":"http://www.serebii.net/pokemongo/pokemon/118.png",
1296 | "type": "Water",
1297 | "height": "0.61 m",
1298 | "weight": "15.0 kg",
1299 | "candy": "50 Goldeen Candy",
1300 | "egg": "5 km"
1301 | },
1302 | {
1303 | "id":"119",
1304 | "num":"119",
1305 | "name":"Seaking",
1306 | "img":"http://www.serebii.net/pokemongo/pokemon/119.png",
1307 | "type": "Water",
1308 | "height": "1.30 m",
1309 | "weight": "39.0 kg",
1310 | "candy": "None",
1311 | "egg": "Not in Eggs"
1312 | },
1313 | {
1314 | "id":"120",
1315 | "num":"120",
1316 | "name":"Staryu",
1317 | "img":"http://www.serebii.net/pokemongo/pokemon/120.png",
1318 | "type": "Water",
1319 | "height": "0.79 m",
1320 | "weight": "34.5 kg",
1321 | "candy": "50 Staryu Candy",
1322 | "egg": "5 km"
1323 | },
1324 | {
1325 | "id":"121",
1326 | "num":"121",
1327 | "name":"Starmie",
1328 | "img":"http://www.serebii.net/pokemongo/pokemon/121.png",
1329 | "type": "Water / Psychic",
1330 | "height": "1.09 m",
1331 | "weight": "80.0 kg",
1332 | "candy": "None",
1333 | "egg": "Not in Eggs"
1334 | },
1335 | {
1336 | "id":"122",
1337 | "num":"122",
1338 | "name":"Mr. Mime",
1339 | "img":"http://www.serebii.net/pokemongo/pokemon/122.png",
1340 | "type": "Psychic",
1341 | "height": "1.30 m",
1342 | "weight": "54.5 kg",
1343 | "candy": "None",
1344 | "egg": "10 km"
1345 | },
1346 | {
1347 | "id":"123",
1348 | "num":"123",
1349 | "name":"Scyther",
1350 | "img":"http://www.serebii.net/pokemongo/pokemon/123.png",
1351 | "type": "Bug / Flying",
1352 | "height": "1.50 m",
1353 | "weight": "56.0 kg",
1354 | "candy": "None",
1355 | "egg": "10 km"
1356 | },
1357 | {
1358 | "id":"124",
1359 | "num":"124",
1360 | "name":"Jynx",
1361 | "img":"http://www.serebii.net/pokemongo/pokemon/124.png",
1362 | "type": "Ice / Psychic",
1363 | "height": "1.40 m",
1364 | "weight": "40.6 kg",
1365 | "candy": "None",
1366 | "egg": "10 km"
1367 | },
1368 | {
1369 | "id":"125",
1370 | "num":"125",
1371 | "name":"Electabuzz",
1372 | "img":"http://www.serebii.net/pokemongo/pokemon/125.png",
1373 | "type": "Electric",
1374 | "height": "1.09 m",
1375 | "weight": "30.0 kg",
1376 | "candy": "None",
1377 | "egg": "10 km"
1378 | },
1379 | {
1380 | "id":"126",
1381 | "num":"126",
1382 | "name":"Magmar",
1383 | "img":"http://www.serebii.net/pokemongo/pokemon/126.png",
1384 | "type": "Fire",
1385 | "height": "1.30 m",
1386 | "weight": "44.5 kg",
1387 | "candy": "None",
1388 | "egg": "10 km"
1389 | },
1390 | {
1391 | "id":"127",
1392 | "num":"127",
1393 | "name":"Pinsir",
1394 | "img":"http://www.serebii.net/pokemongo/pokemon/127.png",
1395 | "type": "Bug",
1396 | "height": "1.50 m",
1397 | "weight": "55.0 kg",
1398 | "candy": "None",
1399 | "egg": "10 km"
1400 | },
1401 | {
1402 | "id":"128",
1403 | "num":"128",
1404 | "name":"Tauros",
1405 | "img":"http://www.serebii.net/pokemongo/pokemon/128.png",
1406 | "type": "Normal",
1407 | "height": "1.40 m",
1408 | "weight": "88.4 kg",
1409 | "candy": "None",
1410 | "egg": "5 km"
1411 | },
1412 | {
1413 | "id":"129",
1414 | "num":"129",
1415 | "name":"Magikarp",
1416 | "img":"http://www.serebii.net/pokemongo/pokemon/129.png",
1417 | "type": "Water",
1418 | "height": "0.89 m",
1419 | "weight": "10.0 kg",
1420 | "candy": "400 Magikarp Candy",
1421 | "egg": "2 km"
1422 | },
1423 | {
1424 | "id":"130",
1425 | "num":"130",
1426 | "name":"Gyarados",
1427 | "img":"http://www.serebii.net/pokemongo/pokemon/130.png",
1428 | "type": "Water / Flying",
1429 | "height": "6.50 m",
1430 | "weight": "235.0 kg",
1431 | "candy": "None",
1432 | "egg": "Not in Eggs"
1433 | },
1434 | {
1435 | "id":"131",
1436 | "num":"131",
1437 | "name":"Lapras",
1438 | "img":"http://www.serebii.net/pokemongo/pokemon/131.png",
1439 | "type": "Water / Ice",
1440 | "height": "2.49 m",
1441 | "weight": "220.0 kg",
1442 | "candy": "None",
1443 | "egg": "10 km"
1444 | },
1445 | {
1446 | "id":"132",
1447 | "num":"132",
1448 | "name":"Ditto",
1449 | "img":"http://www.serebii.net/pokemongo/pokemon/132.png",
1450 | "type": "Normal",
1451 | "height": "0.30 m",
1452 | "weight": "4.0 kg",
1453 | "candy": "None",
1454 | "egg": "Not in Eggs"
1455 | },
1456 | {
1457 | "id":"133",
1458 | "num":"133",
1459 | "name":"Eevee",
1460 | "img":"http://www.serebii.net/pokemongo/pokemon/133.png",
1461 | "type": "Normal",
1462 | "height": "0.30 m",
1463 | "weight": "6.5 kg",
1464 | "candy": "25 Eevee Candy (Evolution decided at random. Or, for first evolution, rename Eevee: Rainer => Vaporeon, Sparky => Jolteon, Pyro => Flareon)",
1465 | "egg": "10 km"
1466 | },
1467 | {
1468 | "id":"134",
1469 | "num":"134",
1470 | "name":"Vaporeon",
1471 | "img":"http://www.serebii.net/pokemongo/pokemon/134.png",
1472 | "type": "Water",
1473 | "height": "0.99 m",
1474 | "weight": "29.0 kg",
1475 | "candy": "None",
1476 | "egg": "Not in Eggs"
1477 | },
1478 | {
1479 | "id":"135",
1480 | "num":"135",
1481 | "name":"Jolteon",
1482 | "img":"http://www.serebii.net/pokemongo/pokemon/135.png",
1483 | "type": "Electric",
1484 | "height": "0.79 m",
1485 | "weight": "24.5 kg",
1486 | "candy": "None",
1487 | "egg": "Not in Eggs"
1488 | },
1489 | {
1490 | "id":"136",
1491 | "num":"136",
1492 | "name":"Flareon",
1493 | "img":"http://www.serebii.net/pokemongo/pokemon/136.png",
1494 | "type": "Fire",
1495 | "height": "0.89 m",
1496 | "weight": "25.0 kg",
1497 | "candy": "None",
1498 | "egg": "Not in Eggs"
1499 | },
1500 | {
1501 | "id":"137",
1502 | "num":"137",
1503 | "name":"Porygon",
1504 | "img":"http://www.serebii.net/pokemongo/pokemon/137.png",
1505 | "type": "Normal",
1506 | "height": "0.79 m",
1507 | "weight": "36.5 kg",
1508 | "candy": "None",
1509 | "egg": "5 km"
1510 | },
1511 | {
1512 | "id":"138",
1513 | "num":"138",
1514 | "name":"Omanyte",
1515 | "img":"http://www.serebii.net/pokemongo/pokemon/138.png",
1516 | "type": "Rock / Water",
1517 | "height": "0.41 m",
1518 | "weight": "7.5 kg",
1519 | "candy": "50 Omanyte Candy",
1520 | "egg": "10 km"
1521 | },
1522 | {
1523 | "id":"139",
1524 | "num":"139",
1525 | "name":"Omastar",
1526 | "img":"http://www.serebii.net/pokemongo/pokemon/139.png",
1527 | "type": "Rock / Water",
1528 | "height": "0.99 m",
1529 | "weight": "35.0 kg",
1530 | "candy": "None",
1531 | "egg": "Not in Eggs"
1532 | },
1533 | {
1534 | "id":"140",
1535 | "num":"140",
1536 | "name":"Kabuto",
1537 | "img":"http://www.serebii.net/pokemongo/pokemon/140.png",
1538 | "type": "Rock / Water",
1539 | "height": "0.51 m",
1540 | "weight": "11.5 kg",
1541 | "candy": "50 Kabuto Candy",
1542 | "egg": "10 km"
1543 | },
1544 | {
1545 | "id":"141",
1546 | "num":"141",
1547 | "name":"Kabutops",
1548 | "img":"http://www.serebii.net/pokemongo/pokemon/141.png",
1549 | "type": "Rock / Water",
1550 | "height": "1.30 m",
1551 | "weight": "40.5 kg",
1552 | "candy": "None",
1553 | "egg": "Not in Eggs"
1554 | },
1555 | {
1556 | "id":"142",
1557 | "num":"142",
1558 | "name":"Aerodactyl",
1559 | "img":"http://www.serebii.net/pokemongo/pokemon/142.png",
1560 | "type": "Rock / Flying",
1561 | "height": "1.80 m",
1562 | "weight": "59.0 kg",
1563 | "candy": "None",
1564 | "egg": "10 km"
1565 | },
1566 | {
1567 | "id":"143",
1568 | "num":"143",
1569 | "name":"Snorlax",
1570 | "img":"http://www.serebii.net/pokemongo/pokemon/143.png",
1571 | "type": "Normal",
1572 | "height": "2.11 m",
1573 | "weight": "460.0 kg",
1574 | "candy": "None",
1575 | "egg": "10 km"
1576 | },
1577 | {
1578 | "id":"144",
1579 | "num":"144",
1580 | "name":"Articuno",
1581 | "img":"http://www.serebii.net/pokemongo/pokemon/144.png",
1582 | "type": "Ice / Flying",
1583 | "height": "1.70 m",
1584 | "weight": "55.4 kg",
1585 | "candy": "None",
1586 | "egg": "Not in Eggs"
1587 | },
1588 | {
1589 | "id":"145",
1590 | "num":"145",
1591 | "name":"Zapdos",
1592 | "img":"http://www.serebii.net/pokemongo/pokemon/145.png",
1593 | "type": "Electric / Flying",
1594 | "height": "1.60 m",
1595 | "weight": "52.6 kg",
1596 | "candy": "None",
1597 | "egg": "Not in Eggs"
1598 | },
1599 | {
1600 | "id":"146",
1601 | "num":"146",
1602 | "name":"Moltres",
1603 | "img":"http://www.serebii.net/pokemongo/pokemon/146.png",
1604 | "type": "Fire / Flying",
1605 | "height": "2.01 m",
1606 | "weight": "60.0 kg",
1607 | "candy": "None",
1608 | "egg": "Not in Eggs"
1609 | },
1610 | {
1611 | "id":"147",
1612 | "num":"147",
1613 | "name":"Dratini",
1614 | "img":"http://www.serebii.net/pokemongo/pokemon/147.png",
1615 | "type": "Dragon",
1616 | "height": "1.80 m",
1617 | "weight": "3.3 kg",
1618 | "candy": "25 Dratini Candy",
1619 | "egg": "10 km"
1620 | },
1621 | {
1622 | "id":"148",
1623 | "num":"148",
1624 | "name":"Dragonair",
1625 | "img":"http://www.serebii.net/pokemongo/pokemon/148.png",
1626 | "type": "Dragon",
1627 | "height": "3.99 m",
1628 | "weight": "16.5 kg",
1629 | "candy": "100 Dratini Candy",
1630 | "egg": "Not in Eggs"
1631 | },
1632 | {
1633 | "id":"149",
1634 | "num":"149",
1635 | "name":"Dragonite",
1636 | "img":"http://www.serebii.net/pokemongo/pokemon/149.png",
1637 | "type": "Dragon / Flying",
1638 | "height": "2.21 m",
1639 | "weight": "210.0 kg",
1640 | "candy": "None",
1641 | "egg": "Not in Eggs"
1642 | },
1643 | {
1644 | "id":"150",
1645 | "num":"150",
1646 | "name":"Mewtwo",
1647 | "img":"http://www.serebii.net/pokemongo/pokemon/150.png",
1648 | "type": "Psychic",
1649 | "height": "2.01 m",
1650 | "weight": "122.0 kg",
1651 | "candy": "None",
1652 | "egg": "Not in Eggs"
1653 | },
1654 | {
1655 | "id":"151",
1656 | "num":"151",
1657 | "name":"Mew",
1658 | "img":"http://www.serebii.net/pokemongo/pokemon/151.png",
1659 | "type": "Psychic",
1660 | "height": "0.41 m",
1661 | "weight": "4.0 kg",
1662 | "candy": "None",
1663 | "egg": "Not in Eggs"
1664 | }
1665 | ]
1666 | }
1667 |
--------------------------------------------------------------------------------
/tests/poke.io/GetLocation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tape');
4 |
5 | var Pokeio = require('../../poke.io.js');
6 | var pokeio = new Pokeio.Pokeio();
7 |
8 | var latitude = 40.4731191;
9 | var longitude = -77.31329079999999;
10 |
11 | pokeio.playerInfo.latitude = latitude;
12 | pokeio.playerInfo.longitude = longitude;
13 |
14 | test('poke.io.GetLocation', function (t) {
15 | t.plan(2);
16 |
17 | pokeio.GetLocation(function(err, address) {
18 | t.error(err, 'No error returned');
19 |
20 | t.equal(address, '355 Lyons Rd, Millerstown, PA 17062, USA', 'Returned exprected address');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/tests/poke.io/GetLocationCoords.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tape');
4 |
5 | var Pokeio = require('../../poke.io.js');
6 | var pokeio = new Pokeio.Pokeio();
7 |
8 | var latitude = 40.4731191;
9 | var longitude = -77.31329079999999;
10 |
11 | pokeio.playerInfo.latitude = latitude;
12 | pokeio.playerInfo.longitude = longitude;
13 |
14 | test('poke.io.GetLocationCoords', function (t) {
15 | t.plan(3);
16 |
17 | var coords = pokeio.GetLocationCoords();
18 |
19 | t.equal(coords.latitude, latitude, 'Returned exprected latitude');
20 | t.equal(coords.longitude, longitude, 'Returned exprected longitude');
21 | t.equal(coords.altitude, 0, 'Returned exprected altitude');
22 | });
23 |
--------------------------------------------------------------------------------
/tests/poke.io/SetLocation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tape');
4 |
5 | var Pokeio = require('../../poke.io.js');
6 | var pokeio = new Pokeio.Pokeio();
7 |
8 | var latitude = 40.4731191;
9 | var longitude = -77.31329079999999;
10 |
11 | test('poke.io.SetLocation - fail to set type', function(t) {
12 | t.plan(2);
13 |
14 | var location = {};
15 |
16 | pokeio.SetLocation(location, function(err, coords) {
17 | t.equal(err.message, 'Invalid location type', 'Returned expected error');
18 | t.error(coords, 'Did not return coords, as expected');
19 | });
20 | });
21 |
22 | test('poke.io.SetLocation - name', function(t) {
23 | t.plan(4);
24 |
25 | var location = {
26 | type: 'name',
27 | name: 'your mom'
28 | };
29 |
30 | pokeio.SetLocation(location, function(err, coords) {
31 | t.error(err, 'No error returned');
32 |
33 | t.equal(coords.latitude, latitude, 'Returned expected latitude');
34 | t.equal(coords.longitude, longitude, 'Returned expected longitude');
35 | t.equal(coords.altitude, 0, 'Returned expected altitude');
36 | });
37 | });
38 |
39 | test('poke.io.SetLocation - fail to set location.name', function(t) {
40 | t.plan(2);
41 |
42 | var location = {
43 | type: 'name',
44 | };
45 |
46 | pokeio.SetLocation(location, function(err, coords) {
47 | t.equal(err.message, 'You should add a location name', 'Returned expected error');
48 | t.error(coords, 'Did not return coords, as expected');
49 | });
50 | });
51 |
52 | test('poke.io.SetLocation - coords', function(t) {
53 | t.plan(4);
54 |
55 | var location = {
56 | type: 'coords',
57 | coords: {
58 | latitude: latitude,
59 | longitude: longitude,
60 | altitude: 0
61 | }
62 | };
63 |
64 | pokeio.SetLocation(location, function(err, coords) {
65 | t.error(err, 'No error returned');
66 |
67 | t.equal(coords.latitude, latitude, 'Returned expected latitude');
68 | t.equal(coords.longitude, longitude, 'Returned expected longitude');
69 | t.equal(coords.altitude, 0, 'Returned expected altitude');
70 | });
71 | });
72 |
73 | test('poke.io.SetLocation - fail to set location.coords object', function(t) {
74 | t.plan(2);
75 |
76 | var location = {
77 | type: 'coords',
78 | };
79 |
80 | pokeio.SetLocation(location, function(err, coords) {
81 | t.equal(err.message, 'Coords object missing', 'Returned expected error');
82 | t.error(coords, 'Did not return coords, as expected');
83 | });
84 | });
85 |
--------------------------------------------------------------------------------