import React from 'react'; import classNames from 'classnames'; import { Grade, ILeaguePokemon, IMaxStats, IStats, } from 'app/models/Pokemon'; import { calculateCp, calculateStatAtLevel } from 'app/utils/calculator'; import { formatDexNumber } from 'app/utils/formatter'; import { IIndividualValues, IndividualValueKey } from './types'; import { LeagueStatsList } from './LeagueStatsList'; import * as styles from './styles/PokemonExplorer.scss'; export interface IPokemonExplorerProps { isLoading : boolean; leaguePokemon : ILeaguePokemon; individualValues : IIndividualValues; handleChangeIndividualValue : (stat : IndividualValueKey, value : number | null) => void; handleMaximizeLevel : () => void; } interface IState { form : { level : string; }; } export class PokemonExplorer extends React.Component { private readonly MIN_LEVEL = 1; private readonly MAX_LEVEL = 40; private readonly MIN_IV = 0; private readonly MAX_IV = 15; private handleChangeHp : (event : React.ChangeEvent) => void; private handleChangeAtk : (event : React.ChangeEvent) => void; private handleChangeDef : (event : React.ChangeEvent) => void; constructor(props : IPokemonExplorerProps) { super(props); this.state = { form: { level: '', } }; this.handleChangeHp = this.handleChangeIvFactory('hp'); this.handleChangeAtk = this.handleChangeIvFactory('atk'); this.handleChangeDef = this.handleChangeIvFactory('def'); } public render() { const { individualValues, leaguePokemon } = this.props; const league = 'great'; // TODO: this should be a prop let rankedPokemon : IStats | null = null; let placeholderLevel = ''; let placeholderHp = ''; let placeholderAtk = ''; let placeholderDef = ''; const dex = formatDexNumber(leaguePokemon.dex); const individualValueLevel = this.state.form.level !== '' ? this.state.form.level : individualValues.level; // default to first pokemon (should be S tier) if (individualValueLevel === null && individualValues.hp === null && individualValues.atk === null && individualValues.def === null ) { rankedPokemon = leaguePokemon.pvp[league][0]; placeholderLevel = '' + rankedPokemon.level; placeholderHp = '' + rankedPokemon.ivHp; placeholderAtk = '' + rankedPokemon.ivAtk; placeholderDef = '' + rankedPokemon.ivDef; // a full spec'd pokemon has been entered } else if (individualValueLevel !== null && typeof individualValueLevel === 'number' && individualValues.hp !== null && individualValues.atk !== null && individualValues.def !== null ) { leaguePokemon.pvp[league].some((stats) => { if (individualValueLevel === stats.level && individualValues.hp === stats.ivHp && individualValues.atk === stats.ivAtk && individualValues.def === 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, individualValueLevel, individualValues.hp, individualValues.atk, individualValues.def), level: individualValueLevel, ivHp: individualValues.hp, ivAtk: individualValues.atk, ivDef: individualValues.def, hp: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseStamina, individualValues.hp), atk: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseAttack, individualValues.atk), def: calculateStatAtLevel(individualValueLevel, leaguePokemon.stats.baseDefense, individualValues.def), 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 = rankedPokemon !== null ? rankedPokemon.hp : '-'; const rankedAtk = rankedPokemon !== null ? rankedPokemon.atk : '-'; const rankedDef = rankedPokemon !== null ? rankedPokemon.def : '-'; const idIvLevelInput = 'iv-level-input'; const idIvHpInput = 'iv-hp-input'; const idIvAtkInput = 'iv-atk-input'; const idIvDefInput = 'iv-def-input'; const containerCss = classNames( 'nes-container', 'with-title' ); const containerRoundCss = classNames( containerCss, 'is-rounded' ); const pokemonType = classNames( containerRoundCss, styles.pokemonType ); const containerTitleCss = classNames( 'title' ); const baseStatsCss = classNames( styles.pokemonBaseStats, containerCss ); const formContainerCss = classNames( containerCss, 'form' ); const fieldCss = classNames( 'nes-field' ); const inlineFieldCss = classNames( fieldCss, 'is-inline', styles.fieldRow ); const inputTextCss = classNames( 'nes-input', styles.ivInput ); const inputTextLevelCss = classNames( inputTextCss, styles.levelInput ); const leaugeRankCss = classNames( styles.leaguePokemonRank, containerCss, { 'with-title': false } ); const maxButtonCss = classNames( 'nes-btn', { 'is-primary': individualValues.hp !== null && individualValues.atk !== null && individualValues.def !== null, 'is-disabled': individualValues.hp === null || individualValues.atk === null || individualValues.def === null, } ); const pokemonIconCss = classNames( `pokemon-${dex}`, { alola: leaguePokemon.form === 'ALOLA' } ); const progressStaminaCss = classNames( 'nes-progress', { 'is-success': leaguePokemon.statsRank.staminaRank > 66, 'is-warning': leaguePokemon.statsRank.staminaRank >= 34 && leaguePokemon.statsRank.staminaRank <= 66, 'is-error': leaguePokemon.statsRank.staminaRank < 34, } ); const progressAttackCss = classNames( 'nes-progress', { 'is-success': leaguePokemon.statsRank.attackRank > 66, 'is-warning': leaguePokemon.statsRank.attackRank >= 34 && leaguePokemon.statsRank.attackRank <= 66, 'is-error': leaguePokemon.statsRank.attackRank < 34, } ); const progressDefenseCss = classNames( 'nes-progress', { 'is-success': leaguePokemon.statsRank.defenseRank > 66, 'is-warning': leaguePokemon.statsRank.defenseRank >= 34 && leaguePokemon.statsRank.defenseRank <= 66, 'is-error': leaguePokemon.statsRank.defenseRank < 34, } ); const baseStamina : number = leaguePokemon.stats.baseStamina; const baseAttack : number = leaguePokemon.stats.baseAttack; const baseDefense : number = leaguePokemon.stats.baseDefense; let type1 : JSX.Element | null = null; if (leaguePokemon.types.type1) { type1 =
{ leaguePokemon.types.type1 }
; } let type2 : JSX.Element | null = null; if (leaguePokemon.types.type2) { type2 =
{ leaguePokemon.types.type2 }
; } return (

No.{ dex }

{ leaguePokemon.form &&
{ leaguePokemon.form.toLowerCase().replace('_', ' ') } Forme
}
{ type1 } { type2 }

{ leaguePokemon.name }

{ leaguePokemon.category }

Base Stats

HP  { baseStamina < 100 && String.fromCharCode(160) }{ baseStamina } { leaguePokemon.statsRank.staminaRank }%
ATK { baseAttack < 100 && String.fromCharCode(160) }{ baseAttack } { leaguePokemon.statsRank.attackRank }%
DEF { baseDefense < 100 && String.fromCharCode(160) }{ baseDefense } { leaguePokemon.statsRank.defenseRank }%
IVs
{ rankedGrade } Rank
CP { rankedCp }
{ rankedHp } HP
{ rankedAtk } ATK
{ rankedDef } DEF
); } private readonly handleChangeLevel = (event : React.ChangeEvent) => { const raw = event.currentTarget.value; const value = parseFloat(raw); this.setState({ form: { level: '' } }); if (raw === '' + value && value >= this.MIN_LEVEL && value <= this.MAX_LEVEL && value % 0.5 === 0) { this.props.handleChangeIndividualValue('level', value); } else if (raw === '') { this.props.handleChangeIndividualValue('level', null); } else if (raw.charAt(raw.length) === '.') { this.setState({ form: { level: raw } }); } } private readonly handleClickMaximizeLevel = () => { this.props.handleMaximizeLevel(); } private readonly handleChangeIvFactory = (type : IndividualValueKey) => { return (event : React.ChangeEvent) => { const raw = event.currentTarget.value; const value = parseInt(raw, 10); if (raw === '' + value && value >= this.MIN_IV && value <= this.MAX_IV) { this.props.handleChangeIndividualValue(type, value); } else if (raw === '') { this.props.handleChangeIndividualValue(type, null); } }; } 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); } }