max level button
This commit is contained in:
parent
44cf0e349c
commit
e43c7edbf2
@ -3,7 +3,7 @@ import PokemonDescription from 'pokemongo-json-pokedex/output/locales/en-US/poke
|
||||
import Pokemon from 'pokemongo-json-pokedex/output/pokemon.json';
|
||||
|
||||
import { LevelMultipliers } from 'app/models/LevelMultipliers';
|
||||
import { Grade, ILeaguePokemon, IPokemon, IStats, League, PokemonIds, Type } from 'app/models/Pokemon';
|
||||
import { Grade, ILeaguePokemon, IPokemon, IStats, League, PokemonId, Type } from 'app/models/Pokemon';
|
||||
|
||||
type ICpAndTotalFound = Record<number, Array<IStats>>;
|
||||
interface IStatsDistribution {
|
||||
@ -65,9 +65,9 @@ Pokemon.forEach((mon) => {
|
||||
const baseAtk = mon.stats.baseAttack;
|
||||
const baseDef = mon.stats.baseDefense;
|
||||
const baseHp = mon.stats.baseStamina;
|
||||
const pokemonDescription = typeof PokemonDescription[mon.id as PokemonIds] !== 'undefined' ? PokemonDescription[mon.id as PokemonIds] : {};
|
||||
const pokemonDescription = typeof PokemonDescription[mon.id as PokemonId] !== 'undefined' ? PokemonDescription[mon.id as PokemonId] : {};
|
||||
const pokemon : ILeaguePokemon = {
|
||||
id: mon.id,
|
||||
id: mon.id as PokemonId,
|
||||
name: pokemonDescription.name || name || 'MissingNo.',
|
||||
category: pokemonDescription.category || '',
|
||||
form,
|
||||
|
||||
@ -36,6 +36,13 @@ body {
|
||||
color: $main-font-primary-color;
|
||||
}
|
||||
|
||||
button.nes-btn:disabled,
|
||||
button.nes-btn:disabled:hover {
|
||||
background-color: $main-font-secondary-color;
|
||||
color: $main-hover-color;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
a.active:not([href]):not([tabindex]) {
|
||||
color: $main-active-font-color;
|
||||
}
|
||||
@ -89,5 +96,10 @@ a.list-item {
|
||||
.nes-input,
|
||||
.nes-textarea {
|
||||
background-color: $main-background-color;
|
||||
outline-color: $main-font-secondary-color;
|
||||
box-shadow: 0 4px $main-border-color, 0 -4px $main-border-color, 4px 0 $main-border-color, -4px 0 $main-border-color;
|
||||
|
||||
&::placeholder {
|
||||
color: $main-font-secondary-color;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +58,7 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps> {
|
||||
leaguePokemon={ leaguePokemon }
|
||||
individualValues={ individualValues }
|
||||
handleChangeIndividualValue={ this.handleChangeIndividualValue }
|
||||
handleMaximizeLevel={ this.handleMaximizeLevel }
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
@ -108,6 +109,10 @@ class PokemonApp extends React.Component<IConnectedPokemonAppProps> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly handleMaximizeLevel = () => {
|
||||
this.props.dispatch(ActionsPokemonExplorer.maximizeLevel());
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state : ReturnType<typeof appReducers>) : PokemonAppProps => {
|
||||
|
||||
@ -4,12 +4,13 @@ import { FixedSizeList } from 'react-window';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { Grade, IStats } from 'app/models/Pokemon';
|
||||
import { Grade, IStats, PokemonId } from 'app/models/Pokemon';
|
||||
import { IIndividualValues } from './types';
|
||||
|
||||
import * as styles from './styles/LeagueStatsList.scss';
|
||||
|
||||
export interface ILeagueStatsListProps {
|
||||
activePokemonId : PokemonId;
|
||||
activeIndividualValues : IIndividualValues;
|
||||
leagueStatsList : Array<IStats>;
|
||||
|
||||
@ -48,7 +49,12 @@ export class LeagueStatsList extends React.Component<ILeagueStatsListProps, ISta
|
||||
|
||||
public componentWillReceiveProps(nextProps : ILeagueStatsListProps) {
|
||||
const activeIvs = nextProps.activeIndividualValues;
|
||||
if (activeIvs.level !== null && activeIvs.hp !== null && activeIvs.atk !== null && activeIvs.def !== null) {
|
||||
if (nextProps.activePokemonId !== this.props.activePokemonId) {
|
||||
this.setState({ activeIndex: -1 });
|
||||
if (this.listRef.current !== null) {
|
||||
this.listRef.current.scrollToItem(0);
|
||||
}
|
||||
} else if (activeIvs.level !== null && activeIvs.hp !== null && activeIvs.atk !== null && activeIvs.def !== null) {
|
||||
let activeIndex = this.state.activeIndex;
|
||||
if (activeIndex === -1) {
|
||||
// there is no current index, wich means the user is entering in the IVs by hand
|
||||
|
||||
@ -18,6 +18,7 @@ export interface IPokemonExplorerProps {
|
||||
individualValues : IIndividualValues;
|
||||
|
||||
handleChangeIndividualValue : (stat : IndividualValueKey, value : number | null) => void;
|
||||
handleMaximizeLevel : () => void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@ -160,6 +161,10 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
||||
'nes-input',
|
||||
styles.ivInput
|
||||
);
|
||||
const inputTextLevelCss = classNames(
|
||||
inputTextCss,
|
||||
styles.levelInput
|
||||
);
|
||||
const leaugeRankCss = classNames(
|
||||
styles.leaguePokemonRank,
|
||||
containerCss,
|
||||
@ -263,7 +268,7 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
||||
name="level"
|
||||
type="number"
|
||||
id={ idIvLevelInput }
|
||||
className={ inputTextCss }
|
||||
className={ inputTextLevelCss }
|
||||
min={ this.MIN_LEVEL }
|
||||
max={ this.MAX_LEVEL }
|
||||
step={ 0.5 }
|
||||
@ -275,9 +280,10 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
||||
<button
|
||||
type="button"
|
||||
className={ maxButtonCss }
|
||||
disabled={ false }
|
||||
disabled={ individualValues.hp === null || individualValues.atk === null || individualValues.def === null }
|
||||
onClick={ this.handleClickMaximizeLevel }
|
||||
>
|
||||
MAX Lv
|
||||
MAX LEAGUE Lv
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
@ -290,6 +296,7 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
||||
</section>
|
||||
</div>
|
||||
<LeagueStatsList
|
||||
activePokemonId={ leaguePokemon.id }
|
||||
activeIndividualValues={ individualValues }
|
||||
leagueStatsList={ leaguePokemon.pvp[league] }
|
||||
handleActivateLeagueStats={ this.handleActivateLeagueStats }
|
||||
@ -312,6 +319,10 @@ export class PokemonExplorer extends React.Component<IPokemonExplorerProps, ISta
|
||||
}
|
||||
}
|
||||
|
||||
private readonly handleClickMaximizeLevel = () => {
|
||||
this.props.handleMaximizeLevel();
|
||||
}
|
||||
|
||||
private readonly handleChangeIvFactory = (type : IndividualValueKey) => {
|
||||
return (event : React.ChangeEvent<HTMLInputElement>) => {
|
||||
const raw = event.currentTarget.value;
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import { action } from 'typesafe-actions';
|
||||
|
||||
import { ThunkResult } from 'app/types';
|
||||
import { PokemonExplorerActionTypes } from './types';
|
||||
|
||||
import { calculateMaxLevelForLeague } from 'app/utils/calculator';
|
||||
|
||||
import { ILeaguePokemon } from 'app/models/Pokemon';
|
||||
|
||||
export const setIsLoading = (isLoading : boolean) => action(PokemonExplorerActionTypes.SET_IS_LOADING, { isLoading });
|
||||
@ -15,3 +18,35 @@ export const setIvHp = (hp : number | null) => action(PokemonExplorerActionTypes
|
||||
export const setIvAtk = (atk : number | null) => action(PokemonExplorerActionTypes.SET_IV_ATK, { atk });
|
||||
|
||||
export const setIvDef = (def : number | null) => action(PokemonExplorerActionTypes.SET_IV_DEF, { def });
|
||||
|
||||
export const maximizeLevel = (
|
||||
) : ThunkResult<Promise<void>> => {
|
||||
return async (dispatch, getState, extraArguments) => {
|
||||
const pokemonExplorerState = getState().pokemonExplorerState;
|
||||
const {
|
||||
hp,
|
||||
atk,
|
||||
def,
|
||||
} = pokemonExplorerState.individualValues;
|
||||
|
||||
if (pokemonExplorerState.leaguePokemon !== null) {
|
||||
const pokemonLeagueValues = pokemonExplorerState.leaguePokemon.pvp[pokemonExplorerState.league];
|
||||
const statsSet = pokemonLeagueValues.some((stats) => {
|
||||
if (((hp === null) || (stats.ivHp === hp)) &&
|
||||
((atk === null) || (stats.ivAtk === atk)) &&
|
||||
((def === null) || (stats.ivDef === def))
|
||||
) {
|
||||
dispatch(setIvHp(stats.ivHp));
|
||||
dispatch(setIvAtk(stats.ivAtk));
|
||||
dispatch(setIvDef(stats.ivDef));
|
||||
dispatch(setIvLevel(stats.level));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!statsSet && hp !== null && atk !== null && def !== null) {
|
||||
dispatch(setIvLevel(calculateMaxLevelForLeague(pokemonExplorerState.leaguePokemon.stats, hp, atk, def, pokemonExplorerState.league)));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -12,6 +12,7 @@ export const initialState : IPokemonExplorerState = {
|
||||
atk: null,
|
||||
def: null,
|
||||
},
|
||||
league: 'great',
|
||||
};
|
||||
|
||||
const reduceSetIsLoading = (
|
||||
|
||||
@ -244,16 +244,24 @@
|
||||
}
|
||||
|
||||
:global(.nes-field.is-inline) .ivInput {
|
||||
flex-grow: 0;
|
||||
width: 3.75rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
width: 4.25em;
|
||||
padding-left: 0.7em;
|
||||
padding-right: 0.5em;
|
||||
|
||||
&.levelInput {
|
||||
width: 6.5em;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.nes-field.is-inline).fieldRow {
|
||||
justify-content: space-evenly;
|
||||
justify-content: space-between;
|
||||
|
||||
label {
|
||||
flex-grow: 0;
|
||||
margin-left: 1em;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ export const fieldRow: string;
|
||||
export const formHeader: string;
|
||||
export const ivInput: string;
|
||||
export const leaguePokemonRank: string;
|
||||
export const levelInput: string;
|
||||
export const pokemonBaseStats: string;
|
||||
export const pokemonInfoLeftColumn: string;
|
||||
export const pokemonInfoRightColumn: string;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ILeaguePokemon } from 'app/models/Pokemon';
|
||||
import { ILeaguePokemon, League } from 'app/models/Pokemon';
|
||||
|
||||
export type IndividualValueKey = 'level' | 'hp' | 'atk' | 'def';
|
||||
export interface IIndividualValues {
|
||||
@ -12,6 +12,7 @@ export interface IPokemonExplorerState {
|
||||
isLoading : boolean;
|
||||
leaguePokemon : ILeaguePokemon | null;
|
||||
individualValues : IIndividualValues;
|
||||
league : League;
|
||||
}
|
||||
|
||||
export const PokemonExplorerActionTypes = {
|
||||
|
||||
@ -33,7 +33,7 @@ interface IRowFactory {
|
||||
}
|
||||
|
||||
export class PokemonSelectList extends React.Component<IPokemonSelectListProps, IState> {
|
||||
private listRef : VariableSizeList | null = null;
|
||||
private listRef : React.RefObject<VariableSizeList>;
|
||||
|
||||
constructor(props : IPokemonSelectListProps) {
|
||||
super(props);
|
||||
@ -44,6 +44,8 @@ export class PokemonSelectList extends React.Component<IPokemonSelectListProps,
|
||||
height: -1,
|
||||
}
|
||||
};
|
||||
|
||||
this.listRef = React.createRef();
|
||||
}
|
||||
|
||||
public render() {
|
||||
@ -93,7 +95,7 @@ export class PokemonSelectList extends React.Component<IPokemonSelectListProps,
|
||||
({ measureRef }) => (
|
||||
<div ref={ measureRef }>
|
||||
<VariableSizeList
|
||||
ref={ this.setListRef }
|
||||
ref={ this.listRef }
|
||||
height={ height }
|
||||
itemKey={ this.getListItemKey }
|
||||
itemCount={ listLength }
|
||||
@ -119,8 +121,6 @@ export class PokemonSelectList extends React.Component<IPokemonSelectListProps,
|
||||
);
|
||||
}
|
||||
|
||||
private readonly setListRef = (element : VariableSizeList) => this.listRef = element;
|
||||
|
||||
private readonly getListItemKey = (index : number) => {
|
||||
return index + this.props.pokemonList[index].id;
|
||||
}
|
||||
@ -166,8 +166,8 @@ export class PokemonSelectList extends React.Component<IPokemonSelectListProps,
|
||||
private readonly handleChangeFilter = (event : React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.handleChangeFilter(event.currentTarget.value)
|
||||
.then(() => {
|
||||
if (this.listRef !== null) {
|
||||
this.listRef.resetAfterIndex(0, true);
|
||||
if (this.listRef.current !== null) {
|
||||
this.listRef.current.resetAfterIndex(0, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ export interface IBaseStats {
|
||||
|
||||
export type Type = 'bug' | 'dark' | 'dragon' | 'electric' | 'fairy' | 'fighting' | 'fire' | 'flying' | 'ghost' | 'grass' | 'ground' | 'ice' | 'normal' | 'poison' | 'psychic' | 'rock' | 'steel' | 'water';
|
||||
export interface IPokemon {
|
||||
id : string;
|
||||
id : PokemonId;
|
||||
name : string;
|
||||
category : string;
|
||||
form : string | null;
|
||||
@ -49,7 +49,7 @@ export interface IStats {
|
||||
metaGrade : Grade;
|
||||
}
|
||||
|
||||
export type PokemonIds = 'BULBASAUR' | 'IVYSAUR' | 'VENUSAUR' | 'CHARMANDER' |
|
||||
export type PokemonId = 'BULBASAUR' | 'IVYSAUR' | 'VENUSAUR' | 'CHARMANDER' |
|
||||
'CHARMELEON' | 'CHARIZARD' | 'SQUIRTLE' | 'WARTORTLE' | 'BLASTOISE' |
|
||||
'CATERPIE' | 'METAPOD' | 'BUTTERFREE' | 'WEEDLE' | 'KAKUNA' | 'BEEDRILL' |
|
||||
'PIDGEY' | 'PIDGEOTTO' | 'PIDGEOT' | 'RATTATA' | 'RATTATA_ALOLA' | 'RATICATE' |
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
import { LevelMultipliers } from 'app/models/LevelMultipliers';
|
||||
import { IBaseStats } from 'app/models/Pokemon';
|
||||
import { IBaseStats, League } from 'app/models/Pokemon';
|
||||
|
||||
const leagueMaxCp = {
|
||||
great: 1500,
|
||||
ultra: 1500
|
||||
};
|
||||
|
||||
const calculateStatsFormula = (baseStats : IBaseStats, ivHp : number, ivAtk : number, ivDef : number) => Math.sqrt(baseStats.baseStamina + ivHp) * Math.sqrt(baseStats.baseDefense + ivDef) * (baseStats.baseAttack + ivAtk);
|
||||
|
||||
export const calculateCp = (baseStats : IBaseStats, level : number, ivHp : number, ivAtk : number, ivDef : number) => {
|
||||
const statsFormula = Math.sqrt(baseStats.baseStamina + ivHp) * Math.sqrt(baseStats.baseDefense + ivDef) * (baseStats.baseAttack + ivAtk);
|
||||
const statsFormula = calculateStatsFormula(baseStats, ivHp, ivAtk, ivDef);
|
||||
const levelMultiplier = LevelMultipliers[(level - 1) * 2];
|
||||
const cp = Math.floor((statsFormula * Math.pow(levelMultiplier, 2)) / 10);
|
||||
return cp;
|
||||
@ -13,3 +20,18 @@ export const calculateStatAtLevel = (level : number, baseStatValue : number, ivS
|
||||
const calculatedStat = Math.floor((baseStatValue + ivStat) * levelMultiplier);
|
||||
return calculatedStat;
|
||||
};
|
||||
|
||||
export const calculateMaxLevelForLeague = (baseStats : IBaseStats, ivHp : number, ivAtk : number, ivDef : number, league : League) => {
|
||||
const maxCp = leagueMaxCp[league];
|
||||
const statsFormula = calculateStatsFormula(baseStats, ivHp, ivAtk, ivDef);
|
||||
let level = 1;
|
||||
for (let i = LevelMultipliers.length - 1; i >= 0; i--) {
|
||||
const levelMultiplier = LevelMultipliers[i];
|
||||
const cp = Math.floor((statsFormula * Math.pow(levelMultiplier, 2)) / 10);
|
||||
if (cp <= maxCp) {
|
||||
level = (i / 2) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user