UNPKG

pogo-data-generator

Version:
1,050 lines (1,049 loc) 60.2 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 tempEvolutions_1 = require("../utils/tempEvolutions"); const enum_1 = require("../utils/enum"); const Item_1 = __importDefault(require("./Item")); const LocationCards_1 = __importDefault(require("./LocationCards")); const Masterfile_1 = __importDefault(require("./Masterfile")); const PokeApi_1 = __importDefault(require("./PokeApi")); const PokemonOverrides_1 = __importDefault(require("./PokemonOverrides")); const reconcileBaseFormChanges = (parsedPokemon, parsedForms, id) => { const pokemon = parsedPokemon[id]; if (!pokemon?.formChanges) { return; } pokemon.forms ?.filter((formId) => formId !== 0) .forEach((formId) => { const form = parsedForms[formId]; if (!form?.formChanges) { return; } const seenFormChanges = new Set(); const baseFormChanges = new Set(pokemon.formChanges.map((formChange) => JSON.stringify(formChange))); const formChanges = form.formChanges.filter((formChange) => { const key = JSON.stringify(formChange); if (seenFormChanges.has(key) || baseFormChanges.has(key)) { return false; } seenFormChanges.add(key); return true; }); if (formChanges.length) { form.formChanges = formChanges; } else { delete form.formChanges; } }); }; const cleanNumberList = (arr) => Array.isArray(arr) ? Array.from(new Set(arr.filter((value) => typeof value === 'number'))) : []; const hasExactPlaceholderMoves = (moves, expected) => moves.length === expected.length && moves.every((value, index) => value === expected[index]); const shouldPreferEstimatedPlaceholderQuickMoves = (actualQuickMoves, actualChargedMoves, fallbackQuickMoves) => hasExactPlaceholderMoves(actualQuickMoves, [pogo_protos_1.Rpc.HoloPokemonMove.SPLASH_FAST]) && hasExactPlaceholderMoves(actualChargedMoves, [pogo_protos_1.Rpc.HoloPokemonMove.STRUGGLE]) && !fallbackQuickMoves.includes(pogo_protos_1.Rpc.HoloPokemonMove.SPLASH_FAST) && fallbackQuickMoves.length > 0; const excludedPlaceholderFallbackChargedMoves = new Set([ pogo_protos_1.Rpc.HoloPokemonMove.FRUSTRATION, pogo_protos_1.Rpc.HoloPokemonMove.RETURN, ]); class Pokemon extends Masterfile_1.default { parsedPokemon; parsedPokeForms; parsedForms; formsRef; generations; lcBanList; evolvedPokemon; options; formsToSkip; evolutionQuests; parsedCostumes; jungleCupRules; constructor(options) { super(); this.options = options; this.formsToSkip = this.options.skipForms ? this.options.skipForms.map((name) => name.toLowerCase()) : []; this.parsedPokemon = {}; this.parsedForms = { 0: { formName: options.unsetFormName ?? 'Unset', proto: 'FORM_UNSET', formId: 0, }, }; this.formsRef = {}; this.evolvedPokemon = new Set(); this.generations = { 1: { name: 'Kanto', range: [1, 151], }, 2: { name: 'Johto', range: [152, 251], }, 3: { name: 'Hoenn', range: [252, 386], }, 4: { name: 'Sinnoh', range: [387, 493], }, 5: { name: 'Unova', range: [494, 649], }, 6: { name: 'Kalos', range: [650, 721], }, 7: { name: 'Alola', range: [722, 809], }, 8: { name: 'Galar', range: [810, 905], }, 9: { name: 'Paldea', range: [906, 1010], }, }; this.evolutionQuests = {}; this.parsedCostumes = {}; this.jungleCupRules = { types: [], banned: [] }; } pokemonName(id) { try { switch (id) { case 29: return 'Nidoran♀'; case 32: return 'Nidoran♂'; default: return this.capitalize(pogo_protos_1.Rpc.HoloPokemonId[id]); } } catch (e) { console.warn(e, `Failed to set pokemon name for ${id}`); } } formName(id, formName) { if (!formName) return ''; try { const name = formName.substring(id === pogo_protos_1.Rpc.HoloPokemonId.NIDORAN_FEMALE || id === pogo_protos_1.Rpc.HoloPokemonId.NIDORAN_MALE ? 8 : pogo_protos_1.Rpc.HoloPokemonId[id].length + 1); return this.capitalize(name); } catch (e) { console.warn(e, `Failed to lookup form name for ${formName}, ID#`, id); } } skipForms(formName) { if (!formName) return false; try { return this.formsToSkip.some((form) => formName.toLowerCase() === form); } catch (e) { console.warn(e, `Failed to skip forms for ${formName}`); } } lookupPokemon(name) { if (!name) return ''; try { for (const key of Object.keys(pogo_protos_1.Rpc.HoloPokemonId)) { if (name.startsWith('PORYGON_Z_')) { return 'PORYGON_Z'; } else if (name.startsWith(`${key}_`)) { return key; } } } catch (e) { console.warn(e, `Failed to lookup pokemon for ${name}`); } } lookupForm(id) { if (!id) return ''; try { return (Object.entries(pogo_protos_1.Rpc.PokemonDisplayProto.Form).find(([_, v]) => { return v === id; })?.[0] || ''); } catch (e) { console.warn(e, `Failed to lookup form for ${id}`); } } getGeneration(id) { try { const genInfo = {}; genInfo.genId = +Object.keys(this.generations).find((gen) => { return (id >= this.generations[gen].range[0] && id <= this.generations[gen].range[1]); }); if (genInfo.genId) { genInfo.generation = this.generations[genInfo.genId].name; } return genInfo; } catch (e) { console.warn(e, `Failed to lookup generation for ${id}`); } } getMoves(moves) { if (!moves) return []; try { return moves .map((move) => typeof move === 'string' ? pogo_protos_1.Rpc.HoloPokemonMove[move] : move) .filter(Boolean) .sort((a, b) => a - b); } catch (e) { console.warn(e, `Failed to lookup moves for ${moves}`); } } getTypes(incomingTypes) { if (!incomingTypes) return []; try { if (!incomingTypes[1]) { incomingTypes.pop(); } return incomingTypes .map((type) => typeof type === 'string' ? pogo_protos_1.Rpc.HoloPokemonType[type] : type) .filter(Boolean) .sort((a, b) => a - b); } catch (e) { console.warn(e, `Failed to lookup types for ${incomingTypes}`); } } getCostumeOverrides(costumes) { try { return costumes.map((costume) => ({ costumeId: pogo_protos_1.Rpc.PokemonDisplayProto.Costume[costume], costumeProto: costume, costumeName: this.capitalize(costume), })); } catch (e) { console.warn('Failed to process costume overrides', e, costumes); } } compileFormChanges(formChanges) { if (!Array.isArray(formChanges)) return []; try { const seenFormChanges = new Set(); return formChanges .map((formChange) => { const availableForms = (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.PokemonDisplayProto.Form, formChange.availableForm || [], 'form'); const questRequirements = formChange.questRequirement ?.map((requirement) => ({ questRequirement: requirement.questRequirementTemplateId, description: requirement.description, target: requirement.target, })) .filter((requirement) => requirement.questRequirement || requirement.description || requirement.target !== undefined) || []; const componentLocationCardSettings = formChange.componentPokemonSettings?.locationCardSettings ?.map((settings) => ({ basePokemonLocationCard: LocationCards_1.default.resolveId(settings.basePokemonLocationCard, 'form change location card'), componentPokemonLocationCard: LocationCards_1.default.resolveId(settings.componentPokemonLocationCard, 'form change location card'), fusionPokemonLocationCard: LocationCards_1.default.resolveId(settings.fusionPokemonLocationCard, 'form change location card'), })) .filter((settings) => Object.values(settings).some((value) => value !== undefined)) || []; const componentPokemonSettings = formChange.componentPokemonSettings ? { pokedexId: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.HoloPokemonId, formChange.componentPokemonSettings.pokedexId, 'pokemon'), formId: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.PokemonDisplayProto.Form, formChange.componentPokemonSettings.form, 'form'), componentCandyCost: formChange.componentPokemonSettings.componentCandyCost, formChangeType: (0, enum_1.enumName)(pogo_protos_1.Rpc.ComponentPokemonSettingsProto.FormChangeType, formChange.componentPokemonSettings.formChangeType, 'form change type'), fusionMove1: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.HoloPokemonMove, formChange.componentPokemonSettings.fusionMove1, 'move'), fusionMove2: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.HoloPokemonMove, formChange.componentPokemonSettings.fusionMove2, 'move'), locationCardSettings: componentLocationCardSettings.length ? componentLocationCardSettings : undefined, familyId: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.HoloPokemonFamilyId, formChange.componentPokemonSettings.familyId, 'family'), } : undefined; const moveReassignment = formChange.moveReassignment ? { quickMoves: formChange.moveReassignment.quickMoves ?.map((moves) => ({ existingMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.existingMoves || [], 'move'), replacementMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.replacementMoves || [], 'move'), })) .filter((moves) => moves.existingMoves.length || moves.replacementMoves.length) || undefined, chargedMoves: formChange.moveReassignment.cinematicMoves ?.map((moves) => ({ existingMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.existingMoves || [], 'move'), replacementMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.replacementMoves || [], 'move'), })) .filter((moves) => moves.existingMoves.length || moves.replacementMoves.length) || undefined, } : undefined; const requiredQuickMoves = formChange.requiredQuickMoves ?.map((moves) => ({ requiredMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.requiredMoves || [], 'move'), })) .filter((moves) => moves.requiredMoves.length) || []; const requiredChargedMoves = formChange.requiredCinematicMoves ?.map((moves) => ({ requiredMoves: (0, enum_1.resolveEnumIds)(pogo_protos_1.Rpc.HoloPokemonMove, moves.requiredMoves || [], 'move'), })) .filter((moves) => moves.requiredMoves.length) || []; const requiredBreadMoves = formChange.requiredBreadMoves ?.map((moves) => { const moveTypes = moves.moveTypes?.filter(Boolean) || []; return { moveTypes: moveTypes.length ? moveTypes : undefined, moveLevel: (0, enum_1.enumName)(pogo_protos_1.Rpc.BreadMoveLevels, moves.moveLevel, 'bread move level'), }; }) .filter((moves) => (moves.moveTypes?.length || 0) > 0 || moves.moveLevel !== undefined) || []; const formChangeBonusAttributes = formChange.formChangeBonusAttributes ?.map((attributes) => { const maxMoves = attributes.maxMoves ?.map((move) => ({ moveType: (0, enum_1.enumName)(pogo_protos_1.Rpc.BreadMoveSlotProto.BreadMoveType, move.moveType, 'bread move type'), moveLevel: (0, enum_1.enumName)(pogo_protos_1.Rpc.BreadMoveLevels, move.moveLevel, 'bread move level'), })) .filter((move) => move.moveType !== undefined || move.moveLevel !== undefined) || []; return { targetForm: (0, enum_1.resolveEnumId)(pogo_protos_1.Rpc.PokemonDisplayProto.Form, attributes.targetForm, 'form'), breadMode: (0, enum_1.enumName)(pogo_protos_1.Rpc.BreadModeEnum.Modifier, attributes.breadMode, 'bread mode'), clearBreadMode: attributes.clearBreadMode, maxMoves: maxMoves.length ? maxMoves : undefined, }; }) .filter((attributes) => Object.entries(attributes).some(([key, value]) => key === 'maxMoves' ? Array.isArray(value) ? value.length > 0 : false : value !== undefined)) || []; const locationCardSettings = formChange.locationCardSettings ?.map((settings) => ({ existingLocationCard: LocationCards_1.default.resolveId(settings.existingLocationCard, 'form change location card'), replacementLocationCard: LocationCards_1.default.resolveId(settings.replacementLocationCard, 'form change location card'), })) .filter((settings) => Object.values(settings).some((value) => value !== undefined)) || []; const normalized = { availableForms: availableForms.length ? availableForms : undefined, candyCost: formChange.candyCost, stardustCost: formChange.stardustCost, itemRequirement: Item_1.default.resolveId(formChange.item, 'form change item'), itemCostCount: formChange.itemCostCount, questRequirements: questRequirements.length ? questRequirements : undefined, componentPokemonSettings: componentPokemonSettings && Object.entries(componentPokemonSettings).some(([key, value]) => key === 'locationCardSettings' ? Array.isArray(value) ? value.length > 0 : false : value !== undefined) ? componentPokemonSettings : undefined, moveReassignment: moveReassignment && (moveReassignment.quickMoves?.length || moveReassignment.chargedMoves?.length) ? moveReassignment : undefined, requiredQuickMoves: requiredQuickMoves.length ? requiredQuickMoves : undefined, requiredChargedMoves: requiredChargedMoves.length ? requiredChargedMoves : undefined, requiredBreadMoves: requiredBreadMoves.length ? requiredBreadMoves : undefined, priority: formChange.priority, formChangeBonusAttributes: formChangeBonusAttributes.length ? formChangeBonusAttributes : undefined, locationCardSettings: locationCardSettings.length ? locationCardSettings : undefined, }; return Object.values(normalized).some((value) => value !== undefined) ? normalized : undefined; }) .filter((formChange) => { if (!formChange) { return false; } const key = JSON.stringify(formChange); if (seenFormChanges.has(key)) { return false; } seenFormChanges.add(key); return true; }); } catch (e) { console.warn(e, `Failed to compile form changes for ${JSON.stringify(formChanges, null, 2)}`); return []; } } compileEvos(mfObject) { const overrides = PokemonOverrides_1.default.checkEvos(this, mfObject); if (overrides) return overrides; try { const evolutions = []; mfObject.forEach((branch) => { if (branch.temporaryEvolution) { return; } else if (branch.evolution) { const id = pogo_protos_1.Rpc.HoloPokemonId[branch.evolution]; const formId = typeof branch.form === 'number' ? branch.form : /^\d+$/.test(branch.form) ? +branch.form : pogo_protos_1.Rpc.PokemonDisplayProto.Form[branch.form]; evolutions.push({ evoId: id, formId: this.options.includeUnset ? formId || 0 : formId, genderRequirement: this.options.genderString ? this.genders[pogo_protos_1.Rpc.PokemonDisplayProto.Gender[branch.genderRequirement]] : pogo_protos_1.Rpc.PokemonDisplayProto.Gender[branch.genderRequirement], candyCost: branch.candyCost, itemRequirement: pogo_protos_1.Rpc.Item[branch.evolutionItemRequirement], tradeBonus: branch.noCandyCostViaTrade, mustBeBuddy: branch.mustBeBuddy, onlyDaytime: branch.onlyDaytime, onlyNighttime: branch.onlyNighttime, questRequirement: branch.questDisplay ? branch.questDisplay[0].questRequirementTemplateId : undefined, }); this.evolvedPokemon.add(id); } }); return evolutions.sort((a, b) => a.evoId - b.evoId); } catch (e) { console.warn(e, `Failed to compile evos for ${JSON.stringify(mfObject, null, 2)}`); } } compileTempEvos(mfObject, evoBranch, primaryForm) { try { const tempEvolutions = mfObject .filter((tempEvo) => tempEvo.stats) .map((tempEvo) => { const resolvedTempEvoId = pogo_protos_1.Rpc.HoloTemporaryEvolutionId[tempEvo.tempEvoId] ?? (tempEvo.tempEvoId === 'TEMP_EVOLUTION_MEGA_Z' ? 5 : tempEvo.tempEvoId); const newTempEvolution = { tempEvoId: resolvedTempEvoId, }; switch (true) { case tempEvo.stats.baseAttack !== primaryForm.attack: case tempEvo.stats.baseDefense !== primaryForm.defense: case tempEvo.stats.baseStamina !== primaryForm.stamina: newTempEvolution.attack = tempEvo.stats.baseAttack; newTempEvolution.defense = tempEvo.stats.baseDefense; newTempEvolution.stamina = tempEvo.stats.baseStamina; } if (tempEvo.averageHeightM !== primaryForm.height) { newTempEvolution.height = tempEvo.averageHeightM; } if (tempEvo.averageWeightKg !== primaryForm.weight) { newTempEvolution.weight = tempEvo.averageWeightKg; } const types = this.getTypes([ tempEvo.typeOverride1, tempEvo.typeOverride2, ]); if (!this.compare(types, primaryForm.types)) { newTempEvolution.types = types; } const energy = evoBranch.find((branch) => branch.temporaryEvolution === tempEvo.tempEvoId); if (energy) { newTempEvolution.firstEnergyCost = energy.temporaryEvolutionEnergyCost; newTempEvolution.subsequentEnergyCost = energy.temporaryEvolutionEnergyCostSubsequent; } return newTempEvolution; }); return (0, tempEvolutions_1.sortTempEvolutions)(tempEvolutions); } catch (e) { console.warn(e, `Failed to compile temp evos for ${JSON.stringify(mfObject, null, 2)}`); } } generateProtoForms() { Object.entries(pogo_protos_1.Rpc.PokemonDisplayProto.Form).forEach((proto) => { const [name, formId] = proto; try { const pokemon = name.startsWith('NIDORAN_') ? ['NIDORAN_FEMALE', 'NIDORAN_MALE'] : [this.formsRef[name] || this.lookupPokemon(name)]; for (const pkmn of pokemon) { if (pkmn) { const id = pogo_protos_1.Rpc.HoloPokemonId[pkmn]; const formName = this.formName(id, name); if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = { pokemonName: this.pokemonName(id), forms: this.options.includeUnset && !this.options.noFormPlaceholders ? [0] : [], pokedexId: id, defaultFormId: 0, ...this.getGeneration(+id), }; } if (!this.skipForms(formName) && !(this.parsedPokemon[id].defaultFormId === 0 && formName === 'Normal' && this.options.skipNormalIfUnset)) { this.parsedForms[formId] = { ...this.parsedForms[formId], formName, proto: name, formId: +formId, }; PokemonOverrides_1.default.addFormData(this, formId); if (!this.parsedPokemon[id].forms.includes(+formId)) { if (!this.parsedPokemon[id].forms) this.parsedPokemon[id].forms = []; this.parsedPokemon[id].forms.push(+formId); } reconcileBaseFormChanges(this.parsedPokemon, this.parsedForms, id); } } } } catch (e) { console.warn(e, '\n', proto); } }); } addExtendedStats(object) { if ('pokemonExtendedSettings' in object.data) { const id = pogo_protos_1.Rpc.HoloPokemonId[object.data.pokemonExtendedSettings.uniqueId]; if (id) { if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = {}; } const values = Object.entries(object.data.pokemonExtendedSettings.sizeSettings).map(([name, value]) => ({ name, value })); const protoForm = object.data.pokemonExtendedSettings.form ? typeof object.data.pokemonExtendedSettings.form === 'number' ? object.data.pokemonExtendedSettings.form : /^\d+$/.test(object.data.pokemonExtendedSettings.form) ? +object.data.pokemonExtendedSettings.form : pogo_protos_1.Rpc.PokemonDisplayProto.Form[object.data.pokemonExtendedSettings.form] : 0; if (protoForm) { if (!this.parsedForms[protoForm]) { this.parsedForms[protoForm] = {}; } this.parsedForms[protoForm].sizeSettings = values; } else { this.parsedPokemon[id].sizeSettings = values; } } } } cleanExtendedStats() { Object.values(this.parsedPokemon).forEach((pkmn) => { if (pkmn.sizeSettings && pkmn.forms) { const pkmnSizeTree = Object.fromEntries(pkmn.sizeSettings.map(({ name, value }) => [name, value])); pkmn.forms.forEach((formId) => { if (this.parsedForms[formId]?.sizeSettings) { if (this.parsedForms[formId].sizeSettings.every((size) => pkmnSizeTree[size.name] === size.value)) { delete this.parsedForms[formId].sizeSettings; } } }); } }); } addFormBaseStats(formId, hp, a, d, sa, sd, sp) { if (this.parsedForms[formId].attack || this.parsedForms[formId].defense || this.parsedForms[formId].stamina) { console.warn('Base stats already found for', pogo_protos_1.Rpc.PokemonDisplayProto.Form[formId]); return; } this.parsedForms[formId].attack = PokeApi_1.default.attack(a, sa, sp); this.parsedForms[formId].defense = PokeApi_1.default.defense(d, sd, sp); this.parsedForms[formId].stamina = PokeApi_1.default.stamina(hp); } addEvolutionQuest(object) { try { const { evolutionQuestTemplate } = object.data; this.evolutionQuests[object.templateId] = { questType: pogo_protos_1.Rpc.QuestType[evolutionQuestTemplate.questType], target: evolutionQuestTemplate.goals[0].target, assetsRef: evolutionQuestTemplate.display.description.toLowerCase(), }; if (this.evolutionQuests[object.templateId].target) { this.evolutionQuests[object.templateId].assetsRef = this.evolutionQuests[object.templateId].assetsRef.replace('single', 'plural'); } if (evolutionQuestTemplate.goals[1]) { console.warn(`Second quest goal detected, fix it. ${object.templateId}`); } } catch (e) { console.warn(e, `Failed to add evolution quest for ${JSON.stringify(object, null, 2)}`); } } addForm(object) { if (object.templateId.split('_')[1]) { const id = Number(object.templateId.split('_')[1].slice(1)); try { const forms = object.data.formSettings.forms; if (forms) { if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = {}; } if (!this.parsedPokemon[id].forms) { this.parsedPokemon[id].forms = []; } for (let i = 0; i < forms.length; i += 1) { const value = forms[i].form; if (!value) continue; const formId = typeof value === 'number' ? value : pogo_protos_1.Rpc.PokemonDisplayProto.Form[value]; const form = typeof value === 'number' ? this.lookupForm(value) : value; this.formsRef[form] = object.data.formSettings.pokemon; const name = this.formName(id, form); if (i === 0) { this.parsedPokemon[id].defaultFormId = formId || 0; } if (!this.skipForms(name)) { this.parsedForms[formId] = { ...this.parsedForms[formId], formName: name, proto: form, formId, isCostume: forms[i].isCostume, }; } } } else { if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = { pokemonName: this.pokemonName(id), forms: [], pokedexId: id, ...this.getGeneration(+id), }; } } reconcileBaseFormChanges(this.parsedPokemon, this.parsedForms, id); if (this.options.includeUnset && !this.options.noFormPlaceholders) { this.parsedPokemon[id].forms.push(0); } } catch (e) { console.warn(e, '\n', JSON.stringify(object, null, 2)); } } } addPokemon(object) { const { templateId, data: { pokemonSettings }, } = object; const split = templateId.split('_'); const id = Number(split[0].slice(1)); try { if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = {}; } const formId = /^V\d{4}_POKEMON_/.test(templateId) ? pogo_protos_1.Rpc.PokemonDisplayProto.Form[templateId.substring('V9999_POKEMON_'.length)] : null; if (formId) { if (!this.parsedPokemon[id].forms) { this.parsedPokemon[id].forms = []; } const primaryForm = this.parsedPokemon[id]; const formName = this.formName(id, split.filter((word, i) => i > 1 && word).join('_')); if (!this.skipForms(formName)) { this.parsedForms[formId] = { ...this.parsedForms[formId], formName, proto: templateId, formId, }; if (!this.parsedPokemon[id].forms.includes(formId)) { this.parsedPokemon[id].forms.push(formId); } const form = this.parsedForms[formId]; switch (true) { case pokemonSettings.stats.baseAttack !== primaryForm.attack: case pokemonSettings.stats.baseDefense !== primaryForm.defense: case pokemonSettings.stats.baseStamina !== primaryForm.stamina: form.attack = pokemonSettings.stats.baseAttack; form.defense = pokemonSettings.stats.baseDefense; form.stamina = pokemonSettings.stats.baseStamina; } switch (true) { case object.data.pokemonSettings.pokedexHeightM !== primaryForm.height: case object.data.pokemonSettings.pokedexWeightKg !== primaryForm.weight: form.height = object.data.pokemonSettings.pokedexHeightM; form.weight = object.data.pokemonSettings.pokedexWeightKg; } const qMoves = this.getMoves(pokemonSettings.quickMoves); if (!this.compare(qMoves, primaryForm.quickMoves)) { form.quickMoves = qMoves; } const cMoves = this.getMoves(pokemonSettings.cinematicMoves); if (!this.compare(cMoves, primaryForm.chargedMoves)) { form.chargedMoves = cMoves; } const eqMoves = this.getMoves(pokemonSettings.eliteQuickMove); if (!this.compare(eqMoves, primaryForm.eliteQuickMoves)) { form.eliteQuickMoves = eqMoves; } const ecMoves = this.getMoves(pokemonSettings.eliteCinematicMove); if (!this.compare(ecMoves, primaryForm.eliteChargedMoves)) { form.eliteChargedMoves = ecMoves; } const types = this.getTypes([ pokemonSettings.type, pokemonSettings.type2, ]); if (!this.compare(types, primaryForm.types)) { form.types = types; } const family = pogo_protos_1.Rpc.HoloPokemonFamilyId[pokemonSettings.familyId]; if (family !== primaryForm.family) { form.family = family; } if (pokemonSettings.evolutionBranch?.some((evo) => evo.evolution)) { if (!form.evolutions) { form.evolutions = []; } form.evolutions.push(...this.compileEvos(pokemonSettings.evolutionBranch)); } const formChanges = this.compileFormChanges(pokemonSettings.formChange); if (formChanges.length) { form.formChanges = formChanges; } else { delete form.formChanges; } if (pokemonSettings.tempEvoOverrides) { form.tempEvolutions = this.compileTempEvos(pokemonSettings.tempEvoOverrides, pokemonSettings.evolutionBranch, this.parsedPokemon[id]); } if ((form.formName === 'Normal' || form.formName === 'Purified') && primaryForm.tempEvolutions) { form.tempEvolutions = Object.values(primaryForm.tempEvolutions).map((tempEvo) => tempEvo); } if (pokemonSettings.shadow) { form.purificationDust = pokemonSettings.shadow.purificationStardustNeeded; form.purificationCandy = pokemonSettings.shadow.purificationCandyNeeded; } if (pokemonSettings.allowNoevolveEvolution) { form.costumeOverrideEvos = this.getCostumeOverrides(pokemonSettings.allowNoevolveEvolution); } reconcileBaseFormChanges(this.parsedPokemon, this.parsedForms, id); } } else { this.parsedPokemon[id] = { pokemonName: this.pokemonName(id), forms: this.parsedPokemon[id].forms || [], ...this.parsedPokemon[id], pokedexId: id, types: this.getTypes([pokemonSettings.type, pokemonSettings.type2]), attack: pokemonSettings.stats.baseAttack, defense: pokemonSettings.stats.baseDefense, stamina: pokemonSettings.stats.baseStamina, height: pokemonSettings.pokedexHeightM, weight: pokemonSettings.pokedexWeightKg, eliteQuickMoves: this.getMoves(pokemonSettings.eliteQuickMove), eliteChargedMoves: this.getMoves(pokemonSettings.eliteCinematicMove), family: pogo_protos_1.Rpc.HoloPokemonFamilyId[pokemonSettings.familyId], fleeRate: pokemonSettings.encounter.baseFleeRate, captureRate: pokemonSettings.encounter.baseCaptureRate, bonusCandyCapture: pokemonSettings.encounter.bonusCandyCaptureReward, bonusStardustCapture: pokemonSettings.encounter.bonusStardustCaptureReward, legendary: pogo_protos_1.Rpc.HoloPokemonClass[pokemonSettings.pokemonClass] === 1, mythic: pogo_protos_1.Rpc.HoloPokemonClass[pokemonSettings.pokemonClass] === 2, ultraBeast: pogo_protos_1.Rpc.HoloPokemonClass[pokemonSettings.pokemonClass] === 3, buddyGroupNumber: pokemonSettings.buddyGroupNumber, buddyDistance: pokemonSettings.kmBuddyDistance, buddyMegaEnergy: pokemonSettings.buddyWalkedMegaEnergyAward, thirdMoveStardust: pokemonSettings.thirdMove.stardustToUnlock, thirdMoveCandy: pokemonSettings.thirdMove.candyToUnlock, gymDefenderEligible: pokemonSettings.isDeployable, tradable: pokemonSettings.isTradable, transferable: pokemonSettings.isTransferable, ...this.getGeneration(id), }; if (id !== 235) { this.parsedPokemon[id].quickMoves = this.getMoves(pokemonSettings.quickMoves); this.parsedPokemon[id].chargedMoves = this.getMoves(pokemonSettings.cinematicMoves); } else { if (pokemonSettings.quickMoves?.length) console.warn('unexpected Smeargle quick moves', pokemonSettings.quickMoves); if (pokemonSettings.cinematicMoves?.length) console.warn('unexpected Smeargle charged moves', pokemonSettings.cinematicMoves); } if (pokemonSettings.evolutionBranch?.some((evo) => evo.evolution)) { this.parsedPokemon[id].evolutions = this.compileEvos(pokemonSettings.evolutionBranch); } const formChanges = this.compileFormChanges(pokemonSettings.formChange); if (formChanges.length) { this.parsedPokemon[id].formChanges = formChanges; reconcileBaseFormChanges(this.parsedPokemon, this.parsedForms, id); } if (pokemonSettings.tempEvoOverrides) { this.parsedPokemon[id].tempEvolutions = this.compileTempEvos(pokemonSettings.tempEvoOverrides, pokemonSettings.evolutionBranch, this.parsedPokemon[id]); } if (pokemonSettings.allowNoevolveEvolution) { this.parsedPokemon[id].costumeOverrideEvos = this.getCostumeOverrides(pokemonSettings.allowNoevolveEvolution); } if (pokemonSettings.shadow) { this.parsedPokemon[id].purificationDust = pokemonSettings.shadow.purificationStardustNeeded; this.parsedPokemon[id].purificationCandy = pokemonSettings.shadow.purificationCandyNeeded; } } } catch (e) { console.warn(e, `Failed to parse Pokemon for ${id}`, JSON.stringify(object, null, 2)); } } addSourdoughMoveMappings({ data: { sourdoughMoveMappingSettings: { mappings }, }, }) { for (let i = 0; i < mappings.length; i += 1) try { const id = pogo_protos_1.Rpc.HoloPokemonId[mappings[i].pokemonId]; if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = {}; } let target = this.parsedPokemon[id]; if (mappings[i].form) { const rawForm = mappings[i].form; const formId = typeof rawForm === 'number' ? rawForm : /^\d+$/.test(rawForm) ? +rawForm : pogo_protos_1.Rpc.PokemonDisplayProto.Form[rawForm]; if (!this.parsedPokemon[id].forms) { this.parsedPokemon[id].forms = []; } const formProto = typeof rawForm === 'number' ? this.lookupForm(rawForm) : /^\d+$/.test(rawForm) ? this.lookupForm(+rawForm) : rawForm; const formName = this.formName(id, formProto); if (!this.skipForms(formName)) { this.parsedForms[formId] = { ...this.parsedForms[formId], formName, formId, }; if (!this.parsedPokemon[id].forms.includes(formId)) { this.parsedPokemon[id].forms.push(formId); } target = this.parsedForms[formId]; } } target.gmaxMove = pogo_protos_1.Rpc.HoloPokemonMove[mappings[i].move]; } catch (e) { console.warn(e, `Failed to parse gmax move mapping #${i}`, JSON.stringify(mappings[i], null, 2)); } } addSmeargleMovesSettings({ data: { smeargleMovesSettings: { quickMoves, cinematicMoves }, }, }) { const id = 235; if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = {}; } try { this.parsedPokemon[id].quickMoves = this.getMoves(quickMoves); } catch (e) { console.warn(e, `Failed to parse smeargle quick move mapping`, JSON.stringify(quickMoves, null, 2)); } try { this.parsedPokemon[id].chargedMoves = this.getMoves(cinematicMoves); } catch (e) { console.warn(e, `Failed to parse smeargle charged move mapping`, JSON.stringify(cinematicMoves, null, 2)); } } missingPokemon() { Object.values(pogo_protos_1.Rpc.HoloPokemonId).forEach((id) => { try { if (id) { this.parsedPokemon[id] = { pokemonName: this.pokemonName(+id), pokedexId: +id, defaultFormId: 0, types: [], quickMoves: [], chargedMoves: [], eliteQuickMoves: [], eliteChargedMoves: [], ...this.getGeneration(+id), ...this.parsedPokemon[id], }; if (!this.parsedPokemon[id].forms) { this.parsedPokemon[id].forms = this.options.noFormPlaceholders ? [] : [0]; } else if ((this.parsedPokemon[id].forms.length === 0 && !this.options.noFormPlaceholders) || this.parsedPokemon[id].defaultFormId === 0) { this.parsedPokemon[id].forms.push(0); } reconcileBaseFormChanges(this.parsedPokemon, this.parsedForms, +id); } } catch (e) { console.warn(e, `Failed to parse Future Pokemon for ${id}`); } }); } sortForms() { Object.values(this.parsedPokemon).forEach((pokemon) => { try { if (pokemon.forms) { pokemon.forms.sort((a, b) => a - b); } } catch (e) { console.warn(e, `Failed to sort forms for ${pokemon.pokemonName}`); } }); } littleCup() { try { if (this.lcBanList === undefined) { console.warn('Missing little cup ban list from Masterfile'); } else { this.lcBanList.add('FARFETCHD'); this.parsedForms[pogo_protos_1.Rpc.PokemonDisplayProto.Form.FARFETCHD_GALARIAN].little = true; } for (const [id, pokemon] of Object.entries(this.parsedPokemon)) { const allowed = !this.evolvedPokemon.has(+id) && pokemon.evolutions !== undefined; if (allowed || +id === pogo_protos_1.Rpc.HoloPokemonId.DEERLING) { pokemon.little = true; } } } catch (e) { console.warn(e, `Failed to parse Little Cup`); } } jungleCup(object) { const { data: { combatLeague: { pokemonCondition, bannedPokemon }, }, } = object; pokemonCondition.forEach((condition) => { if (condition.type === 'WITH_POKEMON_TYPE') { condition.withPokemonType.pokemonType.forEach((type) => { this.jungleCupRules.types.push(pogo_protos_1.Rpc.HoloPokemonType[type]); }); } }); this.jungleCupRules.banned = bannedPokemon?.map((poke) => { return pogo_protos_1.Rpc.HoloPokemonId[poke]; }) ?? []; } jungleEligibility() { Object.entries(this.parsedPokemon).forEach(([id, pokemon]) => { const allowed = this.jungleCupRules.types.some((type) => pokemon.types.includes(type)) && !this.jungleCupRules.banned.includes(+id); if (allowed) pokemon.jungle = true; }); } makeFormsSeparate() { try { this.parsedPokeForms = {}; Object.values(this.parsedPokemon).forEach((pokemon) => { if (pokemon.forms) { pokemon.forms.forEach((form) => { this.parsedPokeForms[`${pokemon.pokedexId}_${form}`] = { ...pokemon, evolutions: form === 0 ? pokemon.evolutions : undefined, formChanges: form === 0 ? pokemon.formChanges : undefined, tempEvolutions: form === 0 ? pokemon.tempEvolutions : undefined, ...this.parsedForms[form], forms: [form], }; }); } }); } catch (e) { console.warn(e, `Failed to make forms separate`); } } parseCostumes() { Object.entries(pogo_protos_1.Rpc.PokemonDisplayProto.Costume).forEach((proto) => { const [name, id] = proto; this.parsedCostumes[id] = { id: +id, name: this.capitalize(name), proto: name, noEvolve: name.endsWith('_NOEVOLVE'), }; }); } parsePokeApi(baseStats, tempEvos) { if (this.options.includeEstimatedPokemon === true || this.options.includeEstimatedPokemon.baseStats) { Object.keys(baseStats).forEach((id) => { try { if (!this.parsedPokemon[id]) { this.parsedPokemon[id] = { pokemonName: this.pokemonName(+id), pokedexId: +id, defaultFormId: 0, forms: this.options.includeUnset && !this.options.noFormPlaceholders ? [0] : [],