diff --git a/src/scripts/convertGameMasterToJson.js b/src/scripts/convertGameMasterToJson.js new file mode 100644 index 0000000..1707a01 --- /dev/null +++ b/src/scripts/convertGameMasterToJson.js @@ -0,0 +1,6 @@ +const POGOProtos = require('pogo-protos'); +const fs = require('fs'); + +const gamemaster = fs.readFileSync('externals/pokemongo-game-master/versions/latest/GAME_MASTER.protobuf'); +const decoded = POGOProtos.Networking.Responses.DownloadItemTemplatesResponse.decode(gamemaster); +fs.writeFileSync(`gamemaster_${ decoded.timestamp_ms }.json`, JSON.stringify(decoded, null, 2)); diff --git a/generatePokemonData.ts b/src/scripts/generatePokemonData.ts similarity index 97% rename from generatePokemonData.ts rename to src/scripts/generatePokemonData.ts index 418c380..4ab2aa4 100644 --- a/generatePokemonData.ts +++ b/src/scripts/generatePokemonData.ts @@ -26,16 +26,6 @@ const maxPossibleStats : IMaxStats = { level: 40, }; -const getClosestCpMultiplierIndex = (value : number) => { - let i; - for (i = 0; i < LevelMultipliers.length; i++) { - if (value < LevelMultipliers[i]) { - break; - } - } - return Math.max(i - 1, 0); -}; - fs.mkdirSync(outPath, { recursive: true }); (async () => { diff --git a/parseGameMaster.ts b/src/scripts/parseGameMaster.ts similarity index 68% rename from parseGameMaster.ts rename to src/scripts/parseGameMaster.ts index 9606154..bd70469 100644 --- a/parseGameMaster.ts +++ b/src/scripts/parseGameMaster.ts @@ -14,7 +14,9 @@ interface ICalculateRelativeStats { export const parseGameMaster = async () => { const apiService = new ApiService(); // const pokemonForms : { [ key in keyof typeof POGOProtos.Enums.PokemonId ]? : Array } = {}; - const pokemonData : { [ key in keyof typeof POGOProtos.Enums.PokemonId ]? : Array } = {}; + // const pokemonData : { [ key in keyof typeof POGOProtos.Enums.PokemonId ]? : Array } = {}; + const pokemonDataByPokemonId : Map> = new Map(); + const pokemonFormsByPokemonId : Map> = new Map(); const pokemonBaseStamina : Array = []; const pokemonBaseAttack : Array = []; @@ -23,7 +25,6 @@ export const parseGameMaster = async () => { const GameMasterProto = fs.readFileSync('externals/pokemongo-game-master/versions/latest/GAME_MASTER.protobuf'); const GameMaster = POGOProtos.Networking.Responses.DownloadItemTemplatesResponse.decode(GameMasterProto); - // fs.writeFileSync('gamemaster.json', JSON.stringify(decoded, null, 2)); const version = GameMaster.timestamp_ms; @@ -32,14 +33,13 @@ export const parseGameMaster = async () => { continue; } - // ignore *_NORMAL entries - if (entry.template_id.match(/^V(\d{4})_POKEMON_(\w+)(? { staminaRank: -1, }, }; - pokemonData[pokemonId]!.push(mon); + pokemonData.push(mon); + pokemonDataByPokemonId.set(pokemonId, pokemonData); const key = POGOProtos.Enums.PokemonId[mon.id] + POGOProtos.Enums.Form[mon.form]; @@ -84,23 +85,42 @@ export const parseGameMaster = async () => { attackRank: -1, defenseRank: -1, }; - // } else if (entry.template_id.indexOf('FORMS_V') === 0 && entry.form_settings) { - // const pokemonId = entry.form_settings.pokemon || POGOProtos.Enums.PokemonId.MISSINGNO; - // if (entry.form_settings.forms) { - // pokemonForms[pokemonId] = entry.form_settings.forms.reduce((output : Array, form) => { - // if (form.form) { - // output.push(form.form); - // } - // return output; - // }, []); - // } else if (pokemonId) { - // pokemonForms[pokemonId] = [POGOProtos.Enums.Form.FORM_UNSET]; - // } + + } else if (entry.template_id.indexOf('FORMS_V') === 0 && entry.form_settings) { + // typings say `forms` can be undefined, but in practice, it's not + if (entry.form_settings.forms && entry.form_settings.forms.length > 0) { + const pokemonId = entry.form_settings.pokemon || POGOProtos.Enums.PokemonId.MISSINGNO; + // console.log(entry); + let pokemonData = pokemonFormsByPokemonId.get(pokemonId) || []; + pokemonData = entry.form_settings.forms.reduce((output : Array, form) => { + if (form.form) { + output.push(form.form); + } + return output; + }, pokemonData); + pokemonFormsByPokemonId.set(pokemonId, pokemonData); + } } } + // remove pokemon placeholders for ones that have forms + for (const [ pokemonId, forms ] of pokemonFormsByPokemonId) { + let pokemonData = pokemonDataByPokemonId.get(pokemonId); + if (typeof pokemonData === 'undefined' || pokemonData.length === 1) { + continue; + } + pokemonData = pokemonData.reduce((data : Array, pokemon) => { + const pokemonHasForm = forms.some((form) => form === pokemon.form); + if (pokemonHasForm) { + data.push(pokemon); + } + return data; + }, []); + pokemonDataByPokemonId.set(pokemonId, pokemonData); + } + // const orderedPokemon = Object.values(pokemonData).sort((a, b) => { - const orderedPokemon = (Object.values(pokemonData) as unknown as Array>).sort((a, b) => { + const orderedPokemon = Array.from(pokemonDataByPokemonId.values()).sort((a, b) => { return a[0].order - b[0].order; }); orderedPokemon.forEach((value) => { diff --git a/src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx b/src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx index 0e53f51..5b60389 100644 --- a/src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx +++ b/src/ts/app/components/PokemonExplorer/PokemonExplorer.tsx @@ -7,7 +7,7 @@ import classNames from 'classnames'; import { IBestWorstStats, ILeaguePokemon, League } from 'app/models/League'; import { Grade, IStats, } from 'app/models/Pokemon'; import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator'; -import { alolanForms, formatDexNumber, formatForm, formatType } from 'app/utils/formatter'; +import { formatDexNumber, formatForm, formatType, Forms } from 'app/utils/formatter'; import { IIndividualValues, IndividualValueKey } from './types'; @@ -218,7 +218,43 @@ export class PokemonExplorer extends React.Component -1 + normal: Forms.normal.indexOf(leaguePokemon.form) > -1, + alola: Forms.alola.indexOf(leaguePokemon.form) > -1, + westSea: Forms.westSea.indexOf(leaguePokemon.form) > -1, + eastSea: Forms.eastSea.indexOf(leaguePokemon.form) > -1, + frost: Forms.frost.indexOf(leaguePokemon.form) > -1, + fan: Forms.fan.indexOf(leaguePokemon.form) > -1, + mow: Forms.mow.indexOf(leaguePokemon.form) > -1, + wash: Forms.wash.indexOf(leaguePokemon.form) > -1, + heat: Forms.heat.indexOf(leaguePokemon.form) > -1, + sky: Forms.sky.indexOf(leaguePokemon.form) > -1, + land: Forms.land.indexOf(leaguePokemon.form) > -1, + overcast: Forms.overcast.indexOf(leaguePokemon.form) > -1, + sunny: Forms.sunny.indexOf(leaguePokemon.form) > -1, + rainy: Forms.rainy.indexOf(leaguePokemon.form) > -1, + snowy: Forms.snowy.indexOf(leaguePokemon.form) > -1, + attack: Forms.attack.indexOf(leaguePokemon.form) > -1, + defense: Forms.defense.indexOf(leaguePokemon.form) > -1, + speed: Forms.speed.indexOf(leaguePokemon.form) > -1, + altered: Forms.altered.indexOf(leaguePokemon.form) > -1, + origin: Forms.origin.indexOf(leaguePokemon.form) > -1, + fighting: Forms.fighting.indexOf(leaguePokemon.form) > -1, + flying: Forms.flying.indexOf(leaguePokemon.form) > -1, + poison: Forms.poison.indexOf(leaguePokemon.form) > -1, + ground: Forms.ground.indexOf(leaguePokemon.form) > -1, + rock: Forms.rock.indexOf(leaguePokemon.form) > -1, + bug: Forms.bug.indexOf(leaguePokemon.form) > -1, + ghost: Forms.ghost.indexOf(leaguePokemon.form) > -1, + steel: Forms.steel.indexOf(leaguePokemon.form) > -1, + fire: Forms.fire.indexOf(leaguePokemon.form) > -1, + water: Forms.water.indexOf(leaguePokemon.form) > -1, + grass: Forms.grass.indexOf(leaguePokemon.form) > -1, + electric: Forms.electric.indexOf(leaguePokemon.form) > -1, + psychic: Forms.psychic.indexOf(leaguePokemon.form) > -1, + ice: Forms.ice.indexOf(leaguePokemon.form) > -1, + dragon: Forms.dragon.indexOf(leaguePokemon.form) > -1, + dark: Forms.dark.indexOf(leaguePokemon.form) > -1, + fairy: Forms.fairy.indexOf(leaguePokemon.form) > -1, }, ); diff --git a/src/ts/app/components/PokemonSelectList/PokemonSelectList.tsx b/src/ts/app/components/PokemonSelectList/PokemonSelectList.tsx index 853c4ea..344d978 100644 --- a/src/ts/app/components/PokemonSelectList/PokemonSelectList.tsx +++ b/src/ts/app/components/PokemonSelectList/PokemonSelectList.tsx @@ -133,7 +133,9 @@ export class PokemonSelectList extends React.Component { - return index + this.props.pokemonList[index].id; + const { pokemonList } = this.props; + const pokemon = pokemonList[index]; + return `${index}-${pokemon.id}-${pokemon.form}`; } private readonly calculateRowHeight = (index : number) => { @@ -160,7 +162,7 @@ export class PokemonSelectList extends React.Component this.props.handleActivatePokemon(pokemon.id, pokemon.form); return ( { } }; -export const alolanForms = [ - POGOProtos.Enums.Form.RATTATA_ALOLA, - POGOProtos.Enums.Form.RATICATE_ALOLA, - POGOProtos.Enums.Form.RAICHU_ALOLA, - POGOProtos.Enums.Form.SANDSHREW_ALOLA, - POGOProtos.Enums.Form.SANDSLASH_ALOLA, - POGOProtos.Enums.Form.VULPIX_ALOLA, - POGOProtos.Enums.Form.NINETALES_ALOLA, - POGOProtos.Enums.Form.DIGLETT_ALOLA, - POGOProtos.Enums.Form.DUGTRIO_ALOLA, - POGOProtos.Enums.Form.MEOWTH_ALOLA, - POGOProtos.Enums.Form.PERSIAN_ALOLA, - POGOProtos.Enums.Form.GEODUDE_ALOLA, - POGOProtos.Enums.Form.GRAVELER_ALOLA, - POGOProtos.Enums.Form.GOLEM_ALOLA, - POGOProtos.Enums.Form.GRIMER_ALOLA, - POGOProtos.Enums.Form.MUK_ALOLA, - POGOProtos.Enums.Form.EXEGGUTOR_ALOLA, - POGOProtos.Enums.Form.MAROWAK_ALOLA, -]; +export const Forms = { + normal: [ + POGOProtos.Enums.Form.CASTFORM_NORMAL, + POGOProtos.Enums.Form.DEOXYS_NORMAL, + POGOProtos.Enums.Form.RATTATA_NORMAL, + POGOProtos.Enums.Form.RATICATE_NORMAL, + POGOProtos.Enums.Form.RAICHU_NORMAL, + POGOProtos.Enums.Form.SANDSHREW_NORMAL, + POGOProtos.Enums.Form.SANDSLASH_NORMAL, + POGOProtos.Enums.Form.VULPIX_NORMAL, + POGOProtos.Enums.Form.NINETALES_NORMAL, + POGOProtos.Enums.Form.DIGLETT_NORMAL, + POGOProtos.Enums.Form.DUGTRIO_NORMAL, + POGOProtos.Enums.Form.MEOWTH_NORMAL, + POGOProtos.Enums.Form.PERSIAN_NORMAL, + POGOProtos.Enums.Form.GEODUDE_NORMAL, + POGOProtos.Enums.Form.GRAVELER_NORMAL, + POGOProtos.Enums.Form.GOLEM_NORMAL, + POGOProtos.Enums.Form.GRIMER_NORMAL, + POGOProtos.Enums.Form.MUK_NORMAL, + POGOProtos.Enums.Form.EXEGGUTOR_NORMAL, + POGOProtos.Enums.Form.MAROWAK_NORMAL, + POGOProtos.Enums.Form.ROTOM_NORMAL, + POGOProtos.Enums.Form.ARCEUS_NORMAL, + ], + alola: [ + POGOProtos.Enums.Form.RATTATA_ALOLA, + POGOProtos.Enums.Form.RATICATE_ALOLA, + POGOProtos.Enums.Form.RAICHU_ALOLA, + POGOProtos.Enums.Form.SANDSHREW_ALOLA, + POGOProtos.Enums.Form.SANDSLASH_ALOLA, + POGOProtos.Enums.Form.VULPIX_ALOLA, + POGOProtos.Enums.Form.NINETALES_ALOLA, + POGOProtos.Enums.Form.DIGLETT_ALOLA, + POGOProtos.Enums.Form.DUGTRIO_ALOLA, + POGOProtos.Enums.Form.MEOWTH_ALOLA, + POGOProtos.Enums.Form.PERSIAN_ALOLA, + POGOProtos.Enums.Form.GEODUDE_ALOLA, + POGOProtos.Enums.Form.GRAVELER_ALOLA, + POGOProtos.Enums.Form.GOLEM_ALOLA, + POGOProtos.Enums.Form.GRIMER_ALOLA, + POGOProtos.Enums.Form.MUK_ALOLA, + POGOProtos.Enums.Form.EXEGGUTOR_ALOLA, + POGOProtos.Enums.Form.MAROWAK_ALOLA, + ], + plant: [ + POGOProtos.Enums.Form.WORMADAM_PLANT, + POGOProtos.Enums.Form.BURMY_PLANT, + ], + sandy: [ + POGOProtos.Enums.Form.WORMADAM_SANDY, + POGOProtos.Enums.Form.BURMY_SANDY, + ], + trash: [ + POGOProtos.Enums.Form.WORMADAM_TRASH, + POGOProtos.Enums.Form.BURMY_TRASH, + ], + westSea: [ + POGOProtos.Enums.Form.SHELLOS_WEST_SEA, + POGOProtos.Enums.Form.GASTRODON_WEST_SEA, + ], + eastSea: [ + POGOProtos.Enums.Form.SHELLOS_EAST_SEA, + POGOProtos.Enums.Form.GASTRODON_EAST_SEA, + ], + altered: [ + POGOProtos.Enums.Form.GIRATINA_ALTERED, + ], + origin: [ + POGOProtos.Enums.Form.GIRATINA_ORIGIN, + ], + frost: [ + POGOProtos.Enums.Form.ROTOM_FROST, + ], + fan: [ + POGOProtos.Enums.Form.ROTOM_FAN, + ], + mow: [ + POGOProtos.Enums.Form.ROTOM_MOW, + ], + wash: [ + POGOProtos.Enums.Form.ROTOM_WASH, + ], + heat: [ + POGOProtos.Enums.Form.ROTOM_HEAT, + ], + sky: [ + POGOProtos.Enums.Form.SHAYMIN_SKY, + ], + land: [ + POGOProtos.Enums.Form.SHAYMIN_LAND, + ], + overcast: [ + POGOProtos.Enums.Form.CHERRIM_OVERCAST, + ], + sunny: [ + POGOProtos.Enums.Form.CASTFORM_SUNNY, + POGOProtos.Enums.Form.CHERRIM_SUNNY, + ], + rainy: [ + POGOProtos.Enums.Form.CASTFORM_RAINY, + ], + snowy: [ + POGOProtos.Enums.Form.CASTFORM_SNOWY, + ], + attack: [ + POGOProtos.Enums.Form.DEOXYS_ATTACK, + ], + defense: [ + POGOProtos.Enums.Form.DEOXYS_DEFENSE, + ], + speed: [ + POGOProtos.Enums.Form.DEOXYS_SPEED, + ], + fighting: [ + POGOProtos.Enums.Form.ARCEUS_FIGHTING, + ], + flying: [ + POGOProtos.Enums.Form.ARCEUS_FLYING, + ], + poison: [ + POGOProtos.Enums.Form.ARCEUS_POISON, + ], + ground: [ + POGOProtos.Enums.Form.ARCEUS_GROUND, + ], + rock: [ + POGOProtos.Enums.Form.ARCEUS_ROCK, + ], + bug: [ + POGOProtos.Enums.Form.ARCEUS_BUG, + ], + ghost: [ + POGOProtos.Enums.Form.ARCEUS_GHOST, + ], + steel: [ + POGOProtos.Enums.Form.ARCEUS_STEEL, + ], + fire: [ + POGOProtos.Enums.Form.ARCEUS_FIRE, + ], + water: [ + POGOProtos.Enums.Form.ARCEUS_WATER, + ], + grass: [ + POGOProtos.Enums.Form.ARCEUS_GRASS, + ], + electric: [ + POGOProtos.Enums.Form.ARCEUS_ELECTRIC, + ], + psychic: [ + POGOProtos.Enums.Form.ARCEUS_PSYCHIC, + ], + ice: [ + POGOProtos.Enums.Form.ARCEUS_ICE, + ], + dragon: [ + POGOProtos.Enums.Form.ARCEUS_DRAGON, + ], + dark: [ + POGOProtos.Enums.Form.ARCEUS_DARK, + ], + fairy: [ + POGOProtos.Enums.Form.ARCEUS_FAIRY, + ], +}; export const formatForm = (form : POGOProtos.Enums.Form) => { - if (alolanForms.indexOf(form) > -1) { + if (Forms.normal.indexOf(form) > -1) { + return 'Normal'; + } else if (Forms.alola.indexOf(form) > -1) { return 'Alola'; - } else { + } else if (Forms.plant.indexOf(form) > -1) { + return 'Plant'; + } else if (Forms.sandy.indexOf(form) > -1) { + return 'Sandy'; + } else if (Forms.trash.indexOf(form) > -1) { + return 'Trash'; + } else if (Forms.westSea.indexOf(form) > -1) { + return 'West Sea'; + } else if (Forms.eastSea.indexOf(form) > -1) { + return 'East Sea'; + } else if (Forms.frost.indexOf(form) > -1) { + return 'Frost'; + } else if (Forms.fan.indexOf(form) > -1) { + return 'Fan'; + } else if (Forms.mow.indexOf(form) > -1) { + return 'Mow'; + } else if (Forms.wash.indexOf(form) > -1) { + return 'Wash'; + } else if (Forms.heat.indexOf(form) > -1) { + return 'Heat'; + } else if (Forms.sky.indexOf(form) > -1) { + return 'Sky'; + } else if (Forms.land.indexOf(form) > -1) { + return 'Land'; + } else if (Forms.overcast.indexOf(form) > -1) { + return 'Overcast'; + } else if (Forms.sunny.indexOf(form) > -1) { + return 'Sunny'; + } else if (Forms.rainy.indexOf(form) > -1) { + return 'Rainy'; + } else if (Forms.snowy.indexOf(form) > -1) { + return 'Snowy'; + } else if (Forms.attack.indexOf(form) > -1) { + return 'Attack'; + } else if (Forms.defense.indexOf(form) > -1) { + return 'Defense'; + } else if (Forms.speed.indexOf(form) > -1) { + return 'Speed'; + } else if (Forms.altered.indexOf(form) > -1) { + return 'Altered'; + } else if (Forms.origin.indexOf(form) > -1) { + return 'Origin'; + } else if (Forms.fighting.indexOf(form) > -1) { + return 'Fighting'; + } else if (Forms.flying.indexOf(form) > -1) { + return 'Flying'; + } else if (Forms.poison.indexOf(form) > -1) { + return 'Poison'; + } else if (Forms.ground.indexOf(form) > -1) { + return 'Fround'; + } else if (Forms.rock.indexOf(form) > -1) { + return 'Rock'; + } else if (Forms.bug.indexOf(form) > -1) { + return 'Bug'; + } else if (Forms.ghost.indexOf(form) > -1) { + return 'Ghost'; + } else if (Forms.steel.indexOf(form) > -1) { + return 'Steel'; + } else if (Forms.fire.indexOf(form) > -1) { + return 'Fire'; + } else if (Forms.water.indexOf(form) > -1) { + return 'Water'; + } else if (Forms.grass.indexOf(form) > -1) { + return 'Grass'; + } else if (Forms.electric.indexOf(form) > -1) { + return 'Electric'; + } else if (Forms.psychic.indexOf(form) > -1) { + return 'Psychic'; + } else if (Forms.ice.indexOf(form) > -1) { + return 'Ice'; + } else if (Forms.dragon.indexOf(form) > -1) { + return 'Dragon'; + } else if (Forms.dark.indexOf(form) > -1) { + return 'Dark'; + } else if (Forms.fairy.indexOf(form) > -1) { + return 'Fairy'; + } else { return ''; } };