pogo-data-generator
Version:
Pokemon GO project data generator
355 lines (354 loc) • 14.9 kB
JavaScript
;
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;