UNPKG

pogo-data-generator

Version:
355 lines (354 loc) 14.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const pogo_protos_1 = require("@na-ji/pogo-protos"); const Masterfile_1 = __importDefault(require("./Masterfile")); class PokeApi extends Masterfile_1.default { constructor() { super(); this.baseStats = {}; this.tempEvos = {}; this.types = {}; this.maxPokemon = 1008; this.inconsistentStats = { 24: { attack: 167, }, 51: { attack: 167, defense: 134, }, 83: { attack: 124, }, 85: { attack: 218, defense: 140, }, 101: { attack: 173, defense: 173, }, 103: { defense: 149, }, 164: { attack: 145, }, 168: { defense: 124, }, 176: { attack: 139, }, 211: { defense: 138, }, 219: { attack: 139, stamina: 137, }, 222: { defense: 156, stamina: 146, }, 226: { attack: 148, stamina: 163, }, 227: { attack: 148, stamina: 163, }, 241: { attack: 157, }, 292: { stamina: 1, }, 809: { stamina: 264, }, }; } set moves(parsed) { this.moveReference = parsed; } static attack(normal, special, speed, nerf = false) { return Math.round(Math.round(2 * (0.875 * Math.max(normal, special) + 0.125 * Math.min(normal, special))) * (1 + (speed - 75) / 500) * (nerf ? 0.91 : 1)); } static defense(normal, special, speed, nerf = false) { return Math.round(Math.round(2 * (0.625 * Math.max(normal, special) + 0.375 * Math.min(normal, special))) * (1 + (speed - 75) / 500) * (nerf ? 0.91 : 1)); } static stamina(hp, nerf = false) { return nerf ? Math.round((1.75 * hp + 50) * 0.91) : Math.floor(1.75 * hp + 50); } cp(atk, def, sta, cpm) { return Math.floor(((atk + 15) * (def + 15) ** 0.5 * (sta + 15) ** 0.5 * cpm ** 2) / 10); } megaLookup(id, type) { switch (true) { case id.endsWith('mega-y'): return 3; case id.endsWith('mega-x'): return 2; case id.endsWith('mega'): return 1; } return this.capitalize(type); } async setMaxPokemonId() { const { count } = await this.fetch(`https://pokeapi.co/api/v2/pokemon-species/?limit=1&offset=0`); this.maxPokemon = +count; return +count; } async baseStatsApi(parsedPokemon, pokeApiIds) { await Promise.all(Object.keys(parsedPokemon).map(async (id) => { if (!parsedPokemon[id].attack || !parsedPokemon[id].defense || !parsedPokemon[id].stamina || parsedPokemon[id].types.length === 0 || (pokeApiIds && pokeApiIds.includes(+id))) { await this.pokemonApi(id); } })); } async extraPokemon(parsedPokemon) { const extraPokemon = []; for (let i = 1; i <= this.maxPokemon; i++) { if (!parsedPokemon[i]) { extraPokemon.push(i); } } await Promise.all(extraPokemon.map((id) => this.pokemonApi(id))); } async pokemonApi(id) { try { const statsData = await this.fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`); const baseStats = {}; statsData.stats.forEach((stat) => { baseStats[stat.stat.name] = stat.base_stat; }); const initial = { attack: PokeApi.attack(baseStats.attack, baseStats['special-attack'], baseStats.speed), defense: PokeApi.defense(baseStats.defense, baseStats['special-defense'], baseStats.speed), stamina: PokeApi.stamina(baseStats.hp), }; initial.cp = this.cp(initial.attack, initial.defense, initial.stamina, 0.79030001); const nerfCheck = { attack: initial.cp > 4000 ? PokeApi.attack(baseStats.attack, baseStats['special-attack'], baseStats.speed, true) : initial.attack, defense: initial.cp > 4000 ? PokeApi.defense(baseStats.defense, baseStats['special-defense'], baseStats.speed, true) : initial.defense, stamina: initial.cp > 4000 ? PokeApi.stamina(baseStats.hp, true) : initial.stamina, }; this.baseStats[id] = { pokemonName: this.capitalize(statsData.name), quickMoves: statsData.moves .map((move) => pogo_protos_1.Rpc.HoloPokemonMove[`${move.move.name .toUpperCase() .replace(/-/g, '_')}_FAST`]) .filter((move) => move && this.moveReference[move]?.power) .sort((a, b) => a - b), chargedMoves: statsData.moves .map((move) => pogo_protos_1.Rpc.HoloPokemonMove[move.move.name.toUpperCase().replace(/-/g, '_')]) .filter((move) => move && this.moveReference[move]?.power) .sort((a, b) => a - b), attack: this.inconsistentStats[id] ? this.inconsistentStats[id].attack || nerfCheck.attack : nerfCheck.attack, defense: this.inconsistentStats[id] ? this.inconsistentStats[id].defense || nerfCheck.defense : nerfCheck.defense, stamina: this.inconsistentStats[id] ? this.inconsistentStats[id].stamina || nerfCheck.stamina : nerfCheck.stamina, types: statsData.types .map((type) => pogo_protos_1.Rpc.HoloPokemonType[`POKEMON_TYPE_${type.type.name.toUpperCase()}`]) .sort((a, b) => a - b), unreleased: true, }; } catch (e) { console.warn(e, `Failed to parse PokeApi Stats for #${id}`); } } async evoApi(evolvedPokemon, parsedPokemon) { await Promise.all(Object.keys(parsedPokemon).map(async (id) => { try { if (!evolvedPokemon.has(+id)) { const evoData = await this.fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`); if (this.baseStats[id]) { this.baseStats[id].legendary = evoData.is_legendary; this.baseStats[id].mythic = evoData.is_mythical; } if (evoData.evolves_from_species) { const prevEvoId = pogo_protos_1.Rpc.HoloPokemonId[evoData.evolves_from_species.name .toUpperCase() .replace('-', '_')] ?? +evoData.evolves_from_species.url.split('/').at(-2); if (prevEvoId) { if (!this.baseStats[prevEvoId]) { this.baseStats[prevEvoId] = {}; } if (!this.baseStats[prevEvoId].evolutions) { this.baseStats[prevEvoId].evolutions = []; } this.baseStats[prevEvoId].evolutions.push({ evoId: +id, formId: parsedPokemon[id]?.defaultFormId || +Object.keys(parsedPokemon[id]?.forms || {})[0] || 0, }); this.baseStats[prevEvoId].evolutions.sort((a, b) => a.evoId - b.evoId); evolvedPokemon.add(+id); } else { console.warn('Unable to find proto ID for', evoData.evolves_from_species.name .toUpperCase() .replace('-', '_')); } } } } catch (e) { console.warn(e, `Failed to parse PokeApi Evolutions for #${id}`); } })); } async tempEvoApi(parsedPokemon) { const theoretical = { mega: [ 'alakazam-mega', 'kangaskhan-mega', 'pinsir-mega', 'aerodactyl-mega', 'mewtwo-mega-x', 'mewtwo-mega-y', 'steelix-mega', 'scizor-mega', 'heracross-mega', 'tyranitar-mega', 'sceptile-mega', 'blaziken-mega', 'swampert-mega', 'gardevoir-mega', 'sableye-mega', 'mawile-mega', 'aggron-mega', 'medicham-mega', 'sharpedo-mega', 'camerupt-mega', 'banette-mega', 'absol-mega', 'glalie-mega', 'garchomp-mega', 'lucario-mega', 'latias-mega', 'latios-mega', 'rayquaza-mega', 'metagross-mega', 'salamence-mega', 'gallade-mega', 'audino-mega', 'diancie-mega', ], }; for (const [type, ids] of Object.entries(theoretical)) { this.tempEvos[type] = {}; await Promise.all(ids.map(async (id) => { try { const pokemonId = pogo_protos_1.Rpc.HoloPokemonId[id.split('-')[0].toUpperCase()]; const statsData = await this.fetch(`https://pokeapi.co/api/v2/pokemon/${id}/`); const baseStats = {}; statsData.stats.forEach((stat) => { baseStats[stat.stat.name] = stat.base_stat; }); const types = statsData.types .map((type) => pogo_protos_1.Rpc.HoloPokemonType[`POKEMON_TYPE_${type.type.name.toUpperCase()}`]) .sort((a, b) => a - b); const newTheoretical = { tempEvoId: this.megaLookup(id, type), attack: PokeApi.attack(baseStats.attack, baseStats['special-attack'], baseStats.speed), defense: PokeApi.defense(baseStats.defense, baseStats['special-defense'], baseStats.speed), stamina: PokeApi.stamina(baseStats.hp), types: this.compare(types, parsedPokemon[pokemonId].types) ? undefined : types, unreleased: true, }; if (!this.tempEvos[type][pokemonId]) { this.tempEvos[type][pokemonId] = {}; } if (!this.tempEvos[type][pokemonId].tempEvolutions) { this.tempEvos[type][pokemonId].tempEvolutions = []; } if (!parsedPokemon[pokemonId].tempEvolutions || (parsedPokemon[pokemonId].tempEvolutions && !parsedPokemon[pokemonId].tempEvolutions.some((temp) => temp.tempEvoId === newTheoretical.tempEvoId))) { this.tempEvos[type][pokemonId].tempEvolutions.push(newTheoretical); } this.tempEvos[type][pokemonId].tempEvolutions.sort((a, b) => typeof a.tempEvoId === 'number' && typeof b.tempEvoId === 'number' ? a.tempEvoId - b.tempEvoId : a.tempEvoId.toString().localeCompare(b.tempEvoId.toString())); } catch (e) { console.warn(e, `Failed to parse PokeApi ${type} Evos for ${id}`); } })); } } async typesApi() { const getTypeIds = (types) => types .map((type) => pogo_protos_1.Rpc.HoloPokemonType[`POKEMON_TYPE_${type.name.toUpperCase()}`]) .sort((a, b) => a - b); await Promise.all(Object.entries(pogo_protos_1.Rpc.HoloPokemonType).map(async ([type, id]) => { try { const { damage_relations: { double_damage_from, double_damage_to, half_damage_from, half_damage_to, no_damage_from, no_damage_to, }, } = id ? await this.fetch(`https://pokeapi.co/api/v2/type/${type .substring(13) .toLowerCase()}`) : { damage_relations: {} }; this.types[id] = { strengths: id ? getTypeIds(double_damage_to) : [], weaknesses: id ? getTypeIds(double_damage_from) : [], veryWeakAgainst: id ? getTypeIds(no_damage_to) : [], immunes: id ? getTypeIds(no_damage_from) : [], weakAgainst: id ? getTypeIds(half_damage_to) : [], resistances: id ? getTypeIds(half_damage_from) : [], }; } catch (e) { console.warn(`Unable to fetch ${type}`, e); } })); } async getGenerations() { const generations = await this.fetch('https://pokeapi.co/api/v2/generation'); const results = await Promise.all(generations.results.map(async (gen, index) => { const { main_region, pokemon_species, } = await this.fetch(gen.url); const name = this.capitalize(main_region.name); const pokemonIds = pokemon_species.map((pokemon) => +pokemon.url.split('/').at(-2)); const min = Math.min(...pokemonIds); const max = Math.max(...pokemonIds); return { id: index + 1, name, range: [min, max] }; })); return Object.fromEntries(results.map(({ id, ...rest }) => [id, rest])); } } exports.default = PokeApi;