import POGOProtos from 'pogo-protos'; import React from 'react'; import classNames from 'classnames'; import { IBestWorstStats, ILeaguePokemon, League, MaxCpByLeague } from 'app/models/League'; import { Grade, IStats, } from 'app/models/Pokemon'; import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator'; import { formatDexNumber, formatForm, formatType, Forms } from 'app/utils/formatter'; import { IIndividualValues, IndividualValueKey } from './types'; import { IvForm } from './IvForm'; import { LeagueSelector } from './LeagueSelector'; import { LeagueStatsList } from './LeagueStatsList'; import { StatDisplay } from './StatDisplay'; import * as styles from './styles/PokemonExplorer.scss'; export interface IPokemonExplorerProps { isLoading : boolean; activeLeague : League; leaguePokemon : ILeaguePokemon; individualValues : IIndividualValues; handleChangeIndividualValue : (stat : IndividualValueKey, value : number | null) => void; handleMaximizeLevel : () => void; handleChangeLeague : (league : League) => void; } enum IvDisplayMode { MANUAL = 'manual', LIST = 'list', } interface IState { ivDisplayMode : IvDisplayMode; } export class PokemonExplorer extends React.Component { private static calculateStatRanks(rankedPokemon : IStats | null, stats : IBestWorstStats) { const rankedHp = rankedPokemon !== null ? rankedPokemon.hp : 0; const rankedAtk = rankedPokemon !== null ? rankedPokemon.atk : 0; const rankedDef = rankedPokemon !== null ? rankedPokemon.def : 0; const maxStamina = stats.stamina; const staminaStatRank = Math.floor(((rankedHp - maxStamina.worst) / (maxStamina.best - maxStamina.worst)) * 100); const maxAttack = stats.attack; const attackStatRank = Math.floor(((rankedAtk - maxAttack.worst) / (maxAttack.best - maxAttack.worst)) * 100); const maxDefense = stats.defense; const defenseStatRank = Math.floor(((rankedDef - maxDefense.worst) / (maxDefense.best - maxDefense.worst)) * 100); return { rankedHp, rankedAtk, rankedDef, staminaStatRank, attackStatRank, defenseStatRank, }; } constructor(props : IPokemonExplorerProps) { super(props); this.state = { ivDisplayMode: IvDisplayMode.MANUAL, }; } public render() { const { activeLeague, individualValues, leaguePokemon, handleChangeIndividualValue, handleMaximizeLevel, } = this.props; const { ivDisplayMode, } = this.state; let rankedPokemon : IStats | null = null; const dex = formatDexNumber(leaguePokemon.dex); // default to first pokemon (should be S tier) if (individualValues.level === null && individualValues.ivHp === null && individualValues.ivAtk === null && individualValues.ivDef === null ) { rankedPokemon = leaguePokemon.pvp[activeLeague][0]; // a full spec'd pokemon has been entered } else if (individualValues.level !== null && individualValues.ivHp !== null && individualValues.ivAtk !== null && individualValues.ivDef !== null ) { leaguePokemon.pvp[activeLeague].some((stats) => { if (individualValues.level === stats.level && individualValues.ivHp === stats.ivHp && individualValues.ivAtk === stats.ivAtk && individualValues.ivDef === stats.ivDef ) { rankedPokemon = stats; return true; } return false; }); // we don't have the data for this terrible mon if (rankedPokemon === null) { rankedPokemon = { cp: calculateCp(leaguePokemon.stats, individualValues.level, individualValues.ivHp, individualValues.ivAtk, individualValues.ivDef), level: individualValues.level, ivHp: individualValues.ivHp, ivAtk: individualValues.ivAtk, ivDef: individualValues.ivDef, hp: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseStamina, individualValues.ivHp), atk: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseAttack, individualValues.ivAtk), def: calculateStatAtLevel(individualValues.level, leaguePokemon.stats.baseDefense, individualValues.ivDef), total: 0, speciesGrade: Grade.F, metaGrade: Grade.F, }; rankedPokemon.total = rankedPokemon.hp + rankedPokemon.atk + rankedPokemon.def; } } const rankedGrade = rankedPokemon !== null ? Grade[rankedPokemon.speciesGrade] : '-'; const rankedCp = rankedPokemon !== null ? rankedPokemon.cp : '-'; const { rankedHp, rankedAtk, rankedDef, staminaStatRank, attackStatRank, defenseStatRank, } = PokemonExplorer.calculateStatRanks(rankedPokemon, leaguePokemon.statMax[activeLeague]); const containerCss = classNames( 'nes-container', 'with-title', ); const containerRoundCss = classNames( containerCss, 'is-rounded', ); const pokemonType = classNames( containerRoundCss, styles.pokemonType, ); const containerTitleCss = classNames( 'title', ); const ivContainerTitleCss = classNames( containerTitleCss, styles.ivContainerTitle ); const baseStatsCss = classNames( styles.pokemonBaseStats, containerCss, ); const formContainerCss = classNames( containerCss, styles.ivsContainer, 'form', { [ styles.diplayingIvList ]: ivDisplayMode === IvDisplayMode.LIST, } ); const leaugeRankCss = classNames( styles.leaguePokemonRank, containerCss, { 'with-title': false }, ); const pokemonIconCss = classNames( `pokemon-${dex}`, { normal: Forms.normal.indexOf(leaguePokemon.form) > -1, alola: Forms.alola.indexOf(leaguePokemon.form) > -1, plant: Forms.plant.indexOf(leaguePokemon.form) > -1, sandy: Forms.sandy.indexOf(leaguePokemon.form) > -1, trash: Forms.trash.indexOf(leaguePokemon.form) > -1, 'west-sea': Forms.westSea.indexOf(leaguePokemon.form) > -1, 'east-sea': 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, }, ); const type1 : JSX.Element =
{ formatType(leaguePokemon.types.type1) }
; let type2 : JSX.Element | null = null; if (leaguePokemon.types.type2) { type2 =
{ formatType(leaguePokemon.types.type2) }
; } return (

No.{ dex }

{ type1 } { type2 }
{ leaguePokemon.form !== POGOProtos.Enums.Form.FORM_UNSET &&
{ formatForm(leaguePokemon.form) } Form
}

{ leaguePokemon.name }

{ leaguePokemon.genus }

Base Stats

IVs
{ ivDisplayMode === IvDisplayMode.MANUAL && } { ivDisplayMode === IvDisplayMode.LIST && }
Rank
{ rankedPokemon === null || rankedPokemon.cp > MaxCpByLeague[activeLeague] &&

N/A

} { rankedPokemon !== null && rankedPokemon.cp <= MaxCpByLeague[activeLeague] &&

{ rankedGrade }

Rank
}
CP

{ rankedCp }

); } private readonly handleActivateLeagueStats = (stats : IStats) => { const { handleChangeIndividualValue } = this.props; handleChangeIndividualValue('level', stats.level); handleChangeIndividualValue('hp', stats.ivHp); handleChangeIndividualValue('atk', stats.ivAtk); handleChangeIndividualValue('def', stats.ivDef); } private readonly handleLeagueSelect = (league : League) => { this.props.handleChangeLeague(league); } private readonly handleIvDisplayModeManual = () => { this.setState({ ivDisplayMode: IvDisplayMode.MANUAL }); } private readonly handleIvDisplayModeList = () => { this.setState({ ivDisplayMode: IvDisplayMode.LIST }); } }