mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-25 16:26:25 +00:00
Add natures
This commit is contained in:
parent
6dc868272f
commit
8cc1982859
30
index.css
30
index.css
@ -89,11 +89,6 @@ body {
|
||||
line-height: 0.9;
|
||||
}
|
||||
|
||||
#apadLabelMenu {
|
||||
margin-left: 10%;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
#apad > :nth-child(2) {
|
||||
position: relative;
|
||||
right: var(--controls-size);
|
||||
@ -101,12 +96,12 @@ body {
|
||||
|
||||
#apad .apadRectBtn {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding-right: 10%;
|
||||
border-radius: 10%;
|
||||
margin-top: calc(var(--controls-size) * -0.4);
|
||||
bottom: calc(var(--controls-size) * 0.05);
|
||||
left: calc(var(--controls-size) * 0.21);
|
||||
width: calc(var(--controls-size) * 0.6);
|
||||
height: calc(var(--controls-size) * 0.4);
|
||||
height: calc(var(--controls-size) * 0.3);
|
||||
}
|
||||
|
||||
#apad .apadSqBtn {
|
||||
@ -118,21 +113,34 @@ body {
|
||||
#apad .apadBtnContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#apad .apadRectBtnContainer {
|
||||
flex-wrap: wrap;
|
||||
margin-top: calc(var(--controls-size) * -0.8);
|
||||
left: calc(var(--controls-size) * 0.175);
|
||||
height: calc(var(--controls-size) * 0.8);
|
||||
}
|
||||
|
||||
#apad .apadSqBtnContainer {
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
margin-bottom: calc(var(--controls-size) * -0.8);
|
||||
top: calc(var(--controls-size) * -0.9);
|
||||
left: calc(var(--controls-size) * 0.1);
|
||||
width: calc(var(--controls-size) * 0.8);
|
||||
height: calc(var(--controls-size) * 0.8);
|
||||
}
|
||||
|
||||
#touchControls:not([data-ui-mode='STARTER_SELECT']) #apad .apadBtnContainer {
|
||||
#apad .apadRectBtnContainer > #apadMenu {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
#touchControls:not([data-ui-mode='STARTER_SELECT']) #apad .apadRectBtnContainer > #apadCycleNature, #touchControls:not([data-ui-mode='STARTER_SELECT']) #apad .apadSqBtnContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#apad .apadRectBtn + .apadBtnContainer {
|
||||
#apad .apadRectBtnContainer + .apadSqBtnContainer {
|
||||
top: calc(var(--controls-size) * -1.9);
|
||||
left: calc(var(--controls-size) * -0.9);
|
||||
}
|
||||
|
11
index.html
11
index.html
@ -41,10 +41,15 @@
|
||||
<div id="apadCancel" class="apadCircBtn apadBtn" data-key="CANCEL">
|
||||
<text id="apadLabelCancel" class="apadLabel">B</text>
|
||||
</div>
|
||||
<div id="apadMenu" class="apadRectBtn apadBtn" data-key="MENU">
|
||||
<text id="apadLabelMenu" class="apadLabel apadLabelSmall">Menu</text>
|
||||
<div class="apadBtnContainer apadRectBtnContainer">
|
||||
<div id="apadCycleNature" class="apadRectBtn apadBtn" data-key="CYCLE_NATURE">
|
||||
<text class="apadLabel apadLabelSmall">N</text>
|
||||
</div>
|
||||
<div id="apadMenu" class="apadRectBtn apadBtn" data-key="MENU">
|
||||
<text class="apadLabel apadLabelSmall">Menu</text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="apadBtnContainer">
|
||||
<div class="apadBtnContainer apadSqBtnContainer">
|
||||
<div id="apadCycleShiny" class="apadSqBtn apadBtn" data-key="CYCLE_SHINY">
|
||||
<text class="apadLabel apadLabelSmall">R</text>
|
||||
</div>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -25,7 +25,7 @@ import { Gender } from "./data/gender";
|
||||
import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { ArenaTagType, ArenaTrapTag, TrickRoomTag } from "./data/arena-tag";
|
||||
import { Abilities, CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
|
||||
import { Abilities, CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
|
||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||
import { getBiomeKey } from "./arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
@ -39,6 +39,7 @@ import { vouchers } from "./system/voucher";
|
||||
import { loggedInUser, updateUserInfo } from "./account";
|
||||
import { GameDataType } from "./system/game-data";
|
||||
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./anims";
|
||||
import { Nature } from "./data/nature";
|
||||
|
||||
export class LoginPhase extends BattlePhase {
|
||||
private showText: boolean;
|
||||
@ -228,7 +229,7 @@ export class SelectStarterPhase extends BattlePhase {
|
||||
? !starterProps.female ? Gender.MALE : Gender.FEMALE
|
||||
: Gender.GENDERLESS;
|
||||
const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0);
|
||||
const starterPokemon = new PlayerPokemon(this.scene, starter.species, startingLevel, starterProps.abilityIndex, starterProps.formIndex, starterGender, starterProps.shiny, starterIvs);
|
||||
const starterPokemon = new PlayerPokemon(this.scene, starter.species, startingLevel, starterProps.abilityIndex, starterProps.formIndex, starterGender, starterProps.shiny, starterIvs, starter.nature);
|
||||
if (starter.pokerus)
|
||||
starterPokemon.pokerus = true;
|
||||
if (this.scene.gameMode === GameMode.SPLICED_ENDLESS)
|
||||
@ -372,6 +373,9 @@ export class EncounterPhase extends BattlePhase {
|
||||
else {
|
||||
const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
|
||||
battle.enemyParty[e] = new EnemyPokemon(this.scene, enemySpecies, level, false);
|
||||
this.scene.getParty().slice(0, !battle.double ? 1 : 2).reverse().forEach(playerPokemon => {
|
||||
applyAbAttrs(SyncEncounterNatureAbAttr, playerPokemon, null, battle.enemyParty[e]);
|
||||
});
|
||||
}
|
||||
}
|
||||
const enemyPokemon = this.scene.getEnemyParty()[e];
|
||||
|
@ -63,6 +63,7 @@ export enum Button {
|
||||
CYCLE_FORM,
|
||||
CYCLE_GENDER,
|
||||
CYCLE_ABILITY,
|
||||
CYCLE_NATURE,
|
||||
QUICK_START,
|
||||
AUTO,
|
||||
SPEED_UP,
|
||||
@ -575,6 +576,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||
[Button.CYCLE_FORM]: [keyCodes.F],
|
||||
[Button.CYCLE_GENDER]: [keyCodes.G],
|
||||
[Button.CYCLE_ABILITY]: [keyCodes.E],
|
||||
[Button.CYCLE_NATURE]: [keyCodes.N],
|
||||
[Button.QUICK_START]: [keyCodes.Q],
|
||||
[Button.AUTO]: [keyCodes.F2],
|
||||
[Button.SPEED_UP]: [keyCodes.PLUS],
|
||||
@ -1032,6 +1034,8 @@ export default class BattleScene extends Phaser.Scene {
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_GENDER);
|
||||
else if (this.isButtonPressed(Button.CYCLE_ABILITY))
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY);
|
||||
else if (this.isButtonPressed(Button.CYCLE_NATURE))
|
||||
inputSuccess = this.ui.processInput(Button.CYCLE_NATURE);
|
||||
else
|
||||
return;
|
||||
} else if (this.isButtonPressed(Button.SPEED_UP)) {
|
||||
|
@ -1005,6 +1005,18 @@ export class WeightMultiplierAbAttr extends AbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
export class SyncEncounterNatureAbAttr extends AbAttr {
|
||||
constructor() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
apply(pokemon: Pokemon, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
(args[0] as Pokemon).setNature(pokemon.nature);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, isAsync?: boolean, showAbilityInstant?: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
@ -1505,7 +1517,8 @@ export function initAbilities() {
|
||||
.attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(BattlerTagType.IGNORE_FLYING) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY)),
|
||||
new Ability(Abilities.EFFECT_SPORE, "Effect Spore", "Contact with the Pokémon may inflict poison, sleep, or paralysis on its attacker.", 3)
|
||||
.attr(PostDefendContactApplyStatusEffectAbAttr, 10, StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP),
|
||||
new Ability(Abilities.SYNCHRONIZE, "Synchronize (N)", "The attacker will receive the same status condition if it inflicts a burn, poison, or paralysis to the Pokémon.", 3),
|
||||
new Ability(Abilities.SYNCHRONIZE, "Synchronize (N)", "The attacker will receive the same status condition if it inflicts a burn, poison, or paralysis to the Pokémon.", 3)
|
||||
.attr(SyncEncounterNatureAbAttr),
|
||||
new Ability(Abilities.CLEAR_BODY, "Clear Body", "Prevents other Pokémon's moves or Abilities from lowering the Pokémon's stats.", 3)
|
||||
.attr(ProtectStatAbAttr),
|
||||
new Ability(Abilities.NATURAL_CURE, "Natural Cure (N)", "All status conditions heal when the Pokémon switches out.", 3),
|
||||
|
130
src/data/nature.ts
Normal file
130
src/data/nature.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import { Stat, getStatName } from "./pokemon-stat";
|
||||
import * as Utils from "../utils";
|
||||
import { TextStyle, getBBCodeFrag } from "../ui/text";
|
||||
|
||||
export enum Nature {
|
||||
HARDY,
|
||||
LONELY,
|
||||
BRAVE,
|
||||
ADAMANT,
|
||||
NAUGHTY,
|
||||
BOLD,
|
||||
DOCILE,
|
||||
RELAXED,
|
||||
IMPISH,
|
||||
LAX,
|
||||
TIMID,
|
||||
HASTY,
|
||||
SERIOUS,
|
||||
JOLLY,
|
||||
NAIVE,
|
||||
MODEST,
|
||||
MILD,
|
||||
QUIET,
|
||||
BASHFUL,
|
||||
RASH,
|
||||
CALM,
|
||||
GENTLE,
|
||||
SASSY,
|
||||
CAREFUL,
|
||||
QUIRKY
|
||||
}
|
||||
|
||||
export function getNatureName(nature: Nature, includeStatEffects: boolean = false, forStarterSelect: boolean = false): string {
|
||||
let ret = Utils.toReadableString(Nature[nature]);
|
||||
if (includeStatEffects) {
|
||||
const stats = Utils.getEnumValues(Stat).slice(1);
|
||||
let increasedStat: Stat = null;
|
||||
let decreasedStat: Stat = null;
|
||||
for (let stat of stats) {
|
||||
const multiplier = getNatureStatMultiplier(nature, stat);
|
||||
if (multiplier > 1)
|
||||
increasedStat = stat;
|
||||
else
|
||||
decreasedStat = stat;
|
||||
}
|
||||
const textStyle = forStarterSelect ? TextStyle.SUMMARY : TextStyle.WINDOW;
|
||||
if (increasedStat && decreasedStat)
|
||||
ret = `${getBBCodeFrag(`${ret}${!forStarterSelect ? '\n' : ' '}(`, textStyle)}${getBBCodeFrag(`+${getStatName(increasedStat, true)}`, TextStyle.SUMMARY_BLUE)}${getBBCodeFrag('/', textStyle)}${getBBCodeFrag(`-${getStatName(decreasedStat, true)}`, TextStyle.SUMMARY_PINK)}${getBBCodeFrag(')', textStyle)}`;
|
||||
else
|
||||
ret = getBBCodeFrag(`${ret}${!forStarterSelect ? '\n' : ' '}(-)`, textStyle);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function getNatureStatMultiplier(nature: Nature, stat: Stat): number {
|
||||
switch (stat) {
|
||||
case Stat.ATK:
|
||||
switch (nature) {
|
||||
case Nature.LONELY:
|
||||
case Nature.BRAVE:
|
||||
case Nature.ADAMANT:
|
||||
case Nature.NAUGHTY:
|
||||
return 1.1;
|
||||
case Nature.BOLD:
|
||||
case Nature.TIMID:
|
||||
case Nature.MODEST:
|
||||
case Nature.CALM:
|
||||
return 0.9;
|
||||
}
|
||||
break;
|
||||
case Stat.DEF:
|
||||
switch (nature) {
|
||||
case Nature.BOLD:
|
||||
case Nature.RELAXED:
|
||||
case Nature.IMPISH:
|
||||
case Nature.LAX:
|
||||
return 1.1;
|
||||
case Nature.LONELY:
|
||||
case Nature.HASTY:
|
||||
case Nature.MILD:
|
||||
case Nature.GENTLE:
|
||||
return 0.9;
|
||||
}
|
||||
break;
|
||||
case Stat.SPATK:
|
||||
switch (nature) {
|
||||
case Nature.MODEST:
|
||||
case Nature.MILD:
|
||||
case Nature.QUIET:
|
||||
case Nature.RASH:
|
||||
return 1.1;
|
||||
case Nature.ADAMANT:
|
||||
case Nature.IMPISH:
|
||||
case Nature.JOLLY:
|
||||
case Nature.CAREFUL:
|
||||
return 0.9;
|
||||
}
|
||||
break;
|
||||
case Stat.SPDEF:
|
||||
switch (nature) {
|
||||
case Nature.CALM:
|
||||
case Nature.GENTLE:
|
||||
case Nature.SASSY:
|
||||
case Nature.CAREFUL:
|
||||
return 1.1;
|
||||
case Nature.NAUGHTY:
|
||||
case Nature.LAX:
|
||||
case Nature.NAIVE:
|
||||
case Nature.RASH:
|
||||
return 0.9;
|
||||
}
|
||||
break;
|
||||
case Stat.SPD:
|
||||
switch (nature) {
|
||||
case Nature.TIMID:
|
||||
case Nature.HASTY:
|
||||
case Nature.JOLLY:
|
||||
case Nature.NAIVE:
|
||||
return 1.1;
|
||||
case Nature.BRAVE:
|
||||
case Nature.RELAXED:
|
||||
case Nature.QUIET:
|
||||
case Nature.SASSY:
|
||||
return 0.9;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -7,26 +7,26 @@ export enum Stat {
|
||||
SPD
|
||||
};
|
||||
|
||||
export function getStatName(stat: Stat) {
|
||||
export function getStatName(stat: Stat, shorten: boolean = false) {
|
||||
let ret: string;
|
||||
switch (stat) {
|
||||
case Stat.HP:
|
||||
ret = 'Max. HP';
|
||||
ret = !shorten ? 'Max. HP' : 'MaxHP';
|
||||
break;
|
||||
case Stat.ATK:
|
||||
ret = 'Attack';
|
||||
ret = !shorten ? 'Attack' : 'Atk';
|
||||
break;
|
||||
case Stat.DEF:
|
||||
ret = 'Defense';
|
||||
ret = !shorten ? 'Defense' : 'Def';
|
||||
break;
|
||||
case Stat.SPATK:
|
||||
ret = 'Sp. Atk';
|
||||
ret = !shorten ? 'Sp. Atk' : 'SpAtk';
|
||||
break;
|
||||
case Stat.SPDEF:
|
||||
ret = 'Sp. Def';
|
||||
ret = !shorten ? 'Sp. Def' : 'SpDef';
|
||||
break;
|
||||
case Stat.SPD:
|
||||
ret = 'Speed';
|
||||
ret = !shorten ? 'Speed' : 'Spd';
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
@ -7,13 +7,14 @@ import { EGG_SEED, Egg, GachaType, getLegendaryGachaSpeciesForTimestamp, getType
|
||||
import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler";
|
||||
import { ModifierTier } from "./modifier/modifier-type";
|
||||
import { Species } from "./data/species";
|
||||
import Pokemon, { PlayerPokemon } from "./pokemon";
|
||||
import { PlayerPokemon } from "./pokemon";
|
||||
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
||||
import { StatsContainer } from "./ui/stats-container";
|
||||
import { TextStyle, addTextObject } from "./ui/text";
|
||||
import { TextStyle, addBBCodeTextObject, addTextObject } from "./ui/text";
|
||||
import { Gender, getGenderColor, getGenderSymbol } from "./data/gender";
|
||||
import { achvs } from "./system/achv";
|
||||
import { addWindow } from "./ui/window";
|
||||
import { getNatureName } from "./data/nature";
|
||||
|
||||
export class EggHatchPhase extends BattlePhase {
|
||||
private egg: Egg;
|
||||
@ -91,55 +92,58 @@ export class EggHatchPhase extends BattlePhase {
|
||||
this.eggHatchOverlay.setAlpha(0);
|
||||
this.scene.fieldUI.add(this.eggHatchOverlay);
|
||||
|
||||
const infoBg = addWindow(this.scene, 0, 0, 96, 116);
|
||||
const infoBg = addWindow(this.scene, 0, 0, 104, 132);
|
||||
infoBg.setOrigin(0.5, 0.5);
|
||||
|
||||
this.infoContainer = this.scene.add.container(this.eggHatchBg.displayWidth + infoBg.width / 2, this.eggHatchBg.displayHeight / 2);
|
||||
|
||||
this.statsContainer = new StatsContainer(this.scene, -48, -54, true);
|
||||
this.statsContainer = new StatsContainer(this.scene, -48, -64, true);
|
||||
|
||||
this.infoContainer.add(infoBg);
|
||||
this.infoContainer.add(this.statsContainer);
|
||||
|
||||
const pokemonGenderLabelText = addTextObject(this.scene, -16, 32, 'Gender:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
const pokemonGenderLabelText = addTextObject(this.scene, -18, 20, 'Gender:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonGenderLabelText.setOrigin(1, 0);
|
||||
pokemonGenderLabelText.setVisible(false);
|
||||
this.infoContainer.add(pokemonGenderLabelText);
|
||||
|
||||
const pokemonGenderText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
const pokemonGenderText = addTextObject(this.scene, -14, 20, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonGenderText.setOrigin(0, 0);
|
||||
pokemonGenderText.setVisible(false);
|
||||
this.infoContainer.add(pokemonGenderText);
|
||||
|
||||
const pokemonAbilityLabelText = addTextObject(this.scene, -16, 32, 'Ability:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
const pokemonAbilityLabelText = addTextObject(this.scene, -18, 20, 'Ability:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonAbilityLabelText.setOrigin(1, 0);
|
||||
this.infoContainer.add(pokemonAbilityLabelText);
|
||||
|
||||
const pokemonAbilityText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
const pokemonAbilityText = addTextObject(this.scene, -14, 20, '', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonAbilityText.setOrigin(0, 0);
|
||||
this.infoContainer.add(pokemonAbilityText);
|
||||
|
||||
const pokemonNatureLabelText = addTextObject(this.scene, -18, 30, 'Nature:', TextStyle.WINDOW, { fontSize: '64px' });
|
||||
pokemonNatureLabelText.setOrigin(1, 0);
|
||||
this.infoContainer.add(pokemonNatureLabelText);
|
||||
|
||||
const pokemonNatureText = addBBCodeTextObject(this.scene, -14, 30, '', TextStyle.WINDOW, { fontSize: '64px', lineSpacing: 3, maxLines: 2 });
|
||||
pokemonNatureText.setOrigin(0, 0);
|
||||
this.infoContainer.add(pokemonNatureText);
|
||||
|
||||
this.eggHatchContainer.add(this.infoContainer);
|
||||
|
||||
const pokemon = this.generatePokemon();
|
||||
if (pokemon.fusionSpecies)
|
||||
pokemon.clearFusionSpecies();
|
||||
|
||||
let abilityYOffset = 5;
|
||||
|
||||
if (pokemon.gender > Gender.GENDERLESS) {
|
||||
pokemonGenderText.setText(getGenderSymbol(pokemon.gender));
|
||||
pokemonGenderText.setColor(getGenderColor(pokemon.gender));
|
||||
pokemonGenderText.setShadowColor(getGenderColor(pokemon.gender, true));
|
||||
pokemonGenderLabelText.setVisible(true);
|
||||
pokemonGenderText.setVisible(true);
|
||||
|
||||
abilityYOffset = 10;
|
||||
}
|
||||
|
||||
[ pokemonAbilityLabelText, pokemonAbilityText ].map(t => t.y += abilityYOffset);
|
||||
|
||||
pokemonAbilityText.setText(pokemon.getAbility().name);
|
||||
pokemonNatureText.setText(getNatureName(pokemon.nature, true));
|
||||
|
||||
const originalIvs: integer[] = this.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr
|
||||
? this.scene.gameData.dexData[pokemon.species.speciesId].ivs
|
||||
@ -205,7 +209,7 @@ export class EggHatchPhase extends BattlePhase {
|
||||
targets: this.infoContainer,
|
||||
duration: Utils.fixedInt(750),
|
||||
ease: 'Cubic.easeInOut',
|
||||
x: this.eggHatchBg.displayWidth - 48
|
||||
x: this.eggHatchBg.displayWidth - 52
|
||||
});
|
||||
|
||||
this.scene.playSoundWithoutBgm('evolution_fanfare');
|
||||
|
@ -33,6 +33,7 @@ import { LevelMoves } from './data/pokemon-level-moves';
|
||||
import { DamageAchv, achvs } from './system/achv';
|
||||
import { DexAttr } from './system/game-data';
|
||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from '@material/material-color-utilities';
|
||||
import { Nature, getNatureStatMultiplier } from './data/nature';
|
||||
|
||||
export enum FieldPosition {
|
||||
CENTER,
|
||||
@ -62,6 +63,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public hp: integer;
|
||||
public stats: integer[];
|
||||
public ivs: integer[];
|
||||
public nature: Nature;
|
||||
public moveset: PokemonMove[];
|
||||
public status: Status;
|
||||
public friendship: integer;
|
||||
@ -88,7 +90,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
private shinySparkle: Phaser.GameObjects.Sprite;
|
||||
|
||||
constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, ivs?: integer[], dataSource?: Pokemon | PokemonData) {
|
||||
constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) {
|
||||
super(scene, x, y);
|
||||
|
||||
if (!species.isObtainable() && this.isPlayer())
|
||||
@ -123,6 +125,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
this.hp = dataSource.hp;
|
||||
this.stats = dataSource.stats;
|
||||
this.ivs = dataSource.ivs;
|
||||
this.nature = dataSource.nature || 0 as Nature;
|
||||
this.moveset = dataSource.moveset;
|
||||
this.status = dataSource.status;
|
||||
this.friendship = dataSource.friendship !== undefined ? dataSource.friendship : this.species.baseFriendship;
|
||||
@ -146,6 +149,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
Utils.binToDec(Utils.decToBin(this.id).substring(25, 30))
|
||||
];
|
||||
|
||||
this.nature = nature !== undefined
|
||||
? nature
|
||||
: Utils.randSeedInt(25) as Nature;
|
||||
|
||||
if (this.gender === undefined) {
|
||||
if (this.species.malePercent === null)
|
||||
this.gender = Gender.GENDERLESS;
|
||||
@ -519,12 +526,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
if (lastMaxHp && value > lastMaxHp)
|
||||
this.hp += value - lastMaxHp;
|
||||
}
|
||||
} else
|
||||
value = Math.min(value + 5, 99999);
|
||||
} else {
|
||||
value += 5;
|
||||
const natureStatMultiplier = getNatureStatMultiplier(this.nature, s);
|
||||
if (natureStatMultiplier !== 1)
|
||||
value = Math[natureStatMultiplier > 1 ? 'ceil' : 'floor'](value * natureStatMultiplier);
|
||||
value = Math.min(value, 99999);
|
||||
}
|
||||
this.stats[s] = value;
|
||||
}
|
||||
}
|
||||
|
||||
setNature(nature: Nature): void {
|
||||
this.nature = nature;
|
||||
this.calculateStats();
|
||||
}
|
||||
|
||||
getMaxHp(): integer {
|
||||
return this.getStat(Stat.HP);
|
||||
}
|
||||
@ -1725,8 +1742,8 @@ export default interface Pokemon {
|
||||
export class PlayerPokemon extends Pokemon {
|
||||
public compatibleTms: Moves[];
|
||||
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender?: Gender, shiny?: boolean, ivs?: integer[], dataSource?: Pokemon | PokemonData) {
|
||||
super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, ivs, dataSource);
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender?: Gender, shiny?: boolean, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) {
|
||||
super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, ivs, nature, dataSource);
|
||||
|
||||
this.generateCompatibleTms();
|
||||
}
|
||||
@ -1791,7 +1808,7 @@ export class PlayerPokemon extends Pokemon {
|
||||
return new Promise(resolve => {
|
||||
const species = getPokemonSpecies(evolution.speciesId);
|
||||
const formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0);
|
||||
const ret = new PlayerPokemon(this.scene, species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this);
|
||||
const ret = new PlayerPokemon(this.scene, species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this.nature, this);
|
||||
ret.loadAssets().then(() => resolve(ret));
|
||||
});
|
||||
}
|
||||
@ -1822,7 +1839,7 @@ export class PlayerPokemon extends Pokemon {
|
||||
if (this.species.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) {
|
||||
const newEvolution = pokemonEvolutions[this.species.speciesId][1];
|
||||
if (newEvolution.condition.predicate(this)) {
|
||||
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny);
|
||||
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.ivs, this.nature);
|
||||
this.scene.getParty().push(newPokemon);
|
||||
newPokemon.evolve(newEvolution);
|
||||
const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
|
||||
@ -1897,7 +1914,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainer: boolean, dataSource?: PokemonData) {
|
||||
super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource?.formIndex,
|
||||
dataSource?.gender, dataSource ? dataSource.shiny : false, null, dataSource);
|
||||
dataSource?.gender, dataSource ? dataSource.shiny : false, null, dataSource ? dataSource.nature : undefined, dataSource);
|
||||
|
||||
this.trainer = trainer;
|
||||
|
||||
@ -2096,7 +2113,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
this.pokeball = pokeballType;
|
||||
this.metLevel = this.level;
|
||||
this.metBiome = this.scene.arena.biomeType;
|
||||
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, null, this);
|
||||
const newPokemon = new PlayerPokemon(this.scene, this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.ivs, this.nature, this);
|
||||
party.push(newPokemon);
|
||||
ret = newPokemon;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import { VoucherType, vouchers } from "./voucher";
|
||||
import { AES, enc } from "crypto-js";
|
||||
import { Mode } from "../ui/ui";
|
||||
import { loggedInUser, updateUserInfo } from "../account";
|
||||
import { Nature } from "../data/nature";
|
||||
|
||||
const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary
|
||||
|
||||
@ -94,6 +95,7 @@ export interface DexData {
|
||||
export interface DexEntry {
|
||||
seenAttr: bigint;
|
||||
caughtAttr: bigint;
|
||||
natureAttr: integer,
|
||||
seenCount: integer;
|
||||
caughtCount: integer;
|
||||
hatchedCount: integer;
|
||||
@ -121,6 +123,7 @@ export interface DexAttrProps {
|
||||
const systemShortKeys = {
|
||||
seenAttr: '$sa',
|
||||
caughtAttr: '$ca',
|
||||
natureAttr: '$na',
|
||||
seenCount: '$s' ,
|
||||
caughtCount: '$c',
|
||||
ivs: '$i'
|
||||
@ -133,6 +136,7 @@ export class GameData {
|
||||
public secretId: integer;
|
||||
|
||||
public dexData: DexData;
|
||||
private defaultDexData: DexData;
|
||||
|
||||
public unlocks: Unlocks;
|
||||
|
||||
@ -261,6 +265,7 @@ export class GameData {
|
||||
|
||||
this.dexData = Object.assign(this.dexData, systemData.dexData);
|
||||
this.consolidateDexData(this.dexData);
|
||||
this.defaultDexData = null;
|
||||
|
||||
resolve(true);
|
||||
}
|
||||
@ -292,7 +297,7 @@ export class GameData {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return k.endsWith('Attr') ? BigInt(v) : v;
|
||||
return k.endsWith('Attr') && k !== 'natureAttr' ? BigInt(v) : v;
|
||||
}) as SystemSaveData;
|
||||
}
|
||||
|
||||
@ -657,7 +662,7 @@ export class GameData {
|
||||
|
||||
for (let species of allSpecies) {
|
||||
data[species.speciesId] = {
|
||||
seenAttr: 0n, caughtAttr: 0n, seenCount: 0, caughtCount: 0, hatchedCount: 0, ivs: [ 0, 0, 0, 0, 0, 0 ]
|
||||
seenAttr: 0n, caughtAttr: 0n, natureAttr: 0, seenCount: 0, caughtCount: 0, hatchedCount: 0, ivs: [ 0, 0, 0, 0, 0, 0 ]
|
||||
};
|
||||
}
|
||||
|
||||
@ -675,14 +680,24 @@ export class GameData {
|
||||
|
||||
const defaultStarterAttr = DexAttr.NON_SHINY | DexAttr.MALE | DexAttr.ABILITY_1 | DexAttr.DEFAULT_FORM;
|
||||
|
||||
for (let ds of defaultStarters) {
|
||||
let entry = data[ds] as DexEntry;
|
||||
const defaultStarterNatures: Nature[] = [];
|
||||
|
||||
this.scene.executeWithSeedOffset(() => {
|
||||
const neutralNatures = [ Nature.HARDY, Nature.DOCILE, Nature.SERIOUS, Nature.BASHFUL, Nature.QUIRKY ];
|
||||
for (let s = 0; s < defaultStarters.length; s++)
|
||||
defaultStarterNatures.push(Phaser.Math.RND.pick(neutralNatures));
|
||||
}, 0, 'default');
|
||||
|
||||
for (let ds = 0; ds < defaultStarters.length; ds++) {
|
||||
let entry = data[defaultStarters[ds]] as DexEntry;
|
||||
entry.seenAttr = defaultStarterAttr;
|
||||
entry.caughtAttr = defaultStarterAttr;
|
||||
entry.natureAttr = Math.pow(2, defaultStarterNatures[ds] + 1);
|
||||
for (let i in entry.ivs)
|
||||
entry.ivs[i] = 10;
|
||||
}
|
||||
|
||||
this.defaultDexData = Object.assign({}, data);
|
||||
this.dexData = data;
|
||||
}
|
||||
|
||||
@ -702,6 +717,7 @@ export class GameData {
|
||||
const dexEntry = this.dexData[species.speciesId];
|
||||
const caughtAttr = dexEntry.caughtAttr;
|
||||
dexEntry.caughtAttr |= pokemon.getDexAttr();
|
||||
dexEntry.natureAttr |= Math.pow(2, pokemon.nature + 1);
|
||||
if (incrementCount) {
|
||||
if (!fromEgg)
|
||||
dexEntry.caughtCount++;
|
||||
@ -767,6 +783,28 @@ export class GameData {
|
||||
};
|
||||
}
|
||||
|
||||
getSpeciesDefaultNature(species: PokemonSpecies): Nature {
|
||||
const dexEntry = this.dexData[species.speciesId];
|
||||
for (let n = 0; n < 25; n++) {
|
||||
if (dexEntry.natureAttr & Math.pow(2, n + 1))
|
||||
return n as Nature;
|
||||
}
|
||||
return 0 as Nature;
|
||||
}
|
||||
|
||||
getSpeciesDefaultNatureAttr(species: PokemonSpecies): integer {
|
||||
return Math.pow(2, this.getSpeciesDefaultNature(species));
|
||||
}
|
||||
|
||||
getNaturesForAttr(natureAttr: integer): Nature[] {
|
||||
let ret: Nature[] = [];
|
||||
for (let n = 0; n < 25; n++) {
|
||||
if (natureAttr & Math.pow(2, n + 1))
|
||||
ret.push(n);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
getFormIndex(attr: bigint): integer {
|
||||
if (!attr || attr < DexAttr.DEFAULT_FORM)
|
||||
return 0;
|
||||
@ -785,6 +823,8 @@ export class GameData {
|
||||
const entry = dexData[k] as DexEntry;
|
||||
if (!entry.hasOwnProperty('hatchedCount'))
|
||||
entry.hatchedCount = 0;
|
||||
if (!entry.hasOwnProperty('natureAttr') || (entry.caughtAttr && !entry.natureAttr))
|
||||
entry.natureAttr = this.defaultDexData[k].natureAttr || Math.pow(2, Utils.randInt(25, 1));
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ import { BattleType } from "../battle";
|
||||
import BattleScene from "../battle-scene";
|
||||
import { Biome } from "../data/biome";
|
||||
import { Gender } from "../data/gender";
|
||||
import { Nature } from "../data/nature";
|
||||
import { PokeballType } from "../data/pokeball";
|
||||
import { getPokemonSpecies } from "../data/pokemon-species";
|
||||
import { Species } from "../data/species";
|
||||
@ -23,6 +24,7 @@ export default class PokemonData {
|
||||
public hp: integer;
|
||||
public stats: integer[];
|
||||
public ivs: integer[];
|
||||
public nature: Nature;
|
||||
public moveset: PokemonMove[];
|
||||
public status: Status;
|
||||
public friendship: integer;
|
||||
@ -55,6 +57,7 @@ export default class PokemonData {
|
||||
this.hp = source.hp;
|
||||
this.stats = source.stats;
|
||||
this.ivs = source.ivs;
|
||||
this.nature = source.nature !== undefined ? source.nature : 0 as Nature;
|
||||
this.friendship = source.friendship !== undefined ? source.friendship : getPokemonSpecies(this.species).baseFriendship;
|
||||
this.metLevel = source.metLevel || 5;
|
||||
this.metBiome = source.metBiome !== undefined ? source.metBiome : -1;
|
||||
@ -92,7 +95,7 @@ export default class PokemonData {
|
||||
toPokemon(scene: BattleScene, battleType?: BattleType): Pokemon {
|
||||
const species = getPokemonSpecies(this.species);
|
||||
if (this.player)
|
||||
return new PlayerPokemon(scene, species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, null, this);
|
||||
return new PlayerPokemon(scene, species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.ivs, this.nature, this);
|
||||
return new EnemyPokemon(scene, species, this.level, battleType === BattleType.TRAINER, this);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import PokemonSpecies, { SpeciesFormKey, allSpecies, getPokemonSpecies, speciesStarters as speciesStarterValues } from "../data/pokemon-species";
|
||||
import { Species } from "../data/species";
|
||||
import { TextStyle, addTextObject, getTextColor } from "./text";
|
||||
import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text";
|
||||
import { Mode } from "./ui";
|
||||
import MessageUiHandler from "./message-ui-handler";
|
||||
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
|
||||
@ -14,12 +14,15 @@ import * as Utils from "../utils";
|
||||
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
|
||||
import { StatsContainer } from "./stats-container";
|
||||
import { addWindow } from "./window";
|
||||
import { Nature, getNatureName } from "../data/nature";
|
||||
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
|
||||
|
||||
export type StarterSelectCallback = (starters: Starter[]) => void;
|
||||
|
||||
export interface Starter {
|
||||
species: PokemonSpecies;
|
||||
dexAttr: bigint;
|
||||
nature: Nature;
|
||||
pokerus: boolean;
|
||||
}
|
||||
|
||||
@ -36,6 +39,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private pokemonGenderText: Phaser.GameObjects.Text;
|
||||
private pokemonAbilityLabelText: Phaser.GameObjects.Text;
|
||||
private pokemonAbilityText: Phaser.GameObjects.Text;
|
||||
private pokemonNatureLabelText: Phaser.GameObjects.Text;
|
||||
private pokemonNatureText: BBCodeText;
|
||||
private genOptionsText: Phaser.GameObjects.Text;
|
||||
private instructionsText: Phaser.GameObjects.Text;
|
||||
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
||||
@ -44,6 +49,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private genMode: boolean;
|
||||
private statsMode: boolean;
|
||||
private dexAttrCursor: bigint = 0n;
|
||||
private natureCursor: integer = 0;
|
||||
private genCursor: integer = 0;
|
||||
private genScrollCursor: integer = 0;
|
||||
|
||||
@ -55,11 +61,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private pokerusGens: integer[] = [];
|
||||
private pokerusCursors: integer[] = [];
|
||||
private starterAttr: bigint[] = [];
|
||||
private starterNatures: Nature[] = [];
|
||||
private speciesStarterDexEntry: DexEntry;
|
||||
private canCycleShiny: boolean;
|
||||
private canCycleForm: boolean;
|
||||
private canCycleGender: boolean;
|
||||
private canCycleAbility: boolean;
|
||||
private canCycleNature: boolean;
|
||||
private value: integer = 0;
|
||||
|
||||
private assetLoadCancelled: Utils.BooleanHolder;
|
||||
@ -131,10 +139,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonAbilityLabelText.setVisible(false);
|
||||
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
|
||||
|
||||
this.pokemonAbilityText = addTextObject(this.scene, 38, 126, '', TextStyle.SUMMARY, { fontSize: '64px' });
|
||||
this.pokemonAbilityText = addTextObject(this.scene, 34, 126, '', TextStyle.SUMMARY, { fontSize: '64px' });
|
||||
this.pokemonAbilityText.setOrigin(0, 0);
|
||||
this.starterSelectContainer.add(this.pokemonAbilityText);
|
||||
|
||||
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 135, 'Nature:', TextStyle.SUMMARY, { fontSize: '64px' });
|
||||
this.pokemonNatureLabelText.setOrigin(0, 0);
|
||||
this.pokemonNatureLabelText.setVisible(false);
|
||||
this.starterSelectContainer.add(this.pokemonNatureLabelText);
|
||||
|
||||
this.pokemonNatureText = addBBCodeTextObject(this.scene, 34, 135, '', TextStyle.SUMMARY, { fontSize: '64px' });
|
||||
this.pokemonNatureText.setOrigin(0, 0);
|
||||
this.starterSelectContainer.add(this.pokemonNatureText);
|
||||
|
||||
this.genOptionsText = addTextObject(this.scene, 124, 7, '', TextStyle.WINDOW, { fontSize: 72, lineSpacing: 39, align: 'center' });
|
||||
this.genOptionsText.setShadowOffset(4.5, 4.5);
|
||||
this.genOptionsText.setOrigin(0.5, 0);
|
||||
@ -254,7 +271,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
|
||||
this.starterSelectContainer.add(this.pokemonSprite);
|
||||
|
||||
this.instructionsText = addTextObject(this.scene, 4, 140, '', TextStyle.PARTY, { fontSize: '42px' });
|
||||
this.instructionsText = addTextObject(this.scene, 4, 148, '', TextStyle.PARTY, { fontSize: '42px' });
|
||||
this.starterSelectContainer.add(this.instructionsText);
|
||||
|
||||
this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6);
|
||||
@ -422,6 +439,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.starterGens.push(this.getGenCursorWithScroll());
|
||||
this.starterCursors.push(this.cursor);
|
||||
this.starterAttr.push(this.dexAttrCursor);
|
||||
this.starterNatures.push(this.natureCursor as unknown as Nature);
|
||||
if (this.speciesLoaded.get(species.speciesId))
|
||||
species.cry(this.scene);
|
||||
if (this.starterCursors.length === 6 || this.value === 10)
|
||||
@ -453,7 +471,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
switch (button) {
|
||||
case Button.CYCLE_SHINY:
|
||||
if (this.canCycleShiny) {
|
||||
this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, undefined);
|
||||
this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, undefined, undefined);
|
||||
if (this.dexAttrCursor & DexAttr.SHINY)
|
||||
this.scene.playSound('sparkle');
|
||||
else
|
||||
@ -469,13 +487,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
if (this.speciesStarterDexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex))
|
||||
break;
|
||||
} while (newFormIndex !== props.formIndex);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, newFormIndex, undefined, undefined);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, newFormIndex, undefined, undefined, undefined);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
case Button.CYCLE_GENDER:
|
||||
if (this.canCycleGender) {
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, !props.female, undefined);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, !props.female, undefined, undefined);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
@ -496,7 +514,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
break;
|
||||
}
|
||||
} while (newAbilityIndex !== props.abilityIndex);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newAbilityIndex);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newAbilityIndex, undefined);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
case Button.CYCLE_NATURE:
|
||||
if (this.canCycleNature) {
|
||||
const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry.natureAttr);
|
||||
const natureIndex = natures.indexOf(this.natureCursor);
|
||||
const newNature = natures[natureIndex < natures.length - 1 ? natureIndex + 1 : 0];
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, newNature);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
@ -534,14 +561,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
}
|
||||
|
||||
updateInstructions(): void {
|
||||
let instructionLines = [
|
||||
'Arrow Keys/WASD: Move'
|
||||
];
|
||||
let instructionLines = [ ];
|
||||
let cycleInstructionLines = [];
|
||||
if (!this.genMode)
|
||||
instructionLines.push('A/Space/Enter: Select');
|
||||
if (this.starterCursors.length)
|
||||
instructionLines.push('X/Backspace/Esc: Undo');
|
||||
if (this.speciesStarterDexEntry?.caughtAttr) {
|
||||
if (this.canCycleShiny)
|
||||
cycleInstructionLines.push('R: Cycle Shiny');
|
||||
@ -551,6 +572,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
cycleInstructionLines.push('G: Cycle Gender');
|
||||
if (this.canCycleAbility)
|
||||
cycleInstructionLines.push('E: Cycle Ability');
|
||||
if (this.canCycleNature)
|
||||
cycleInstructionLines.push('N: Cycle Nature');
|
||||
}
|
||||
|
||||
if (cycleInstructionLines.length > 2) {
|
||||
@ -656,6 +679,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
setSpecies(species: PokemonSpecies) {
|
||||
this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null;
|
||||
this.dexAttrCursor = species ? this.scene.gameData.getSpeciesDefaultDexAttr(species) : 0n;
|
||||
this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0;
|
||||
|
||||
if (this.statsMode) {
|
||||
if (this.speciesStarterDexEntry?.caughtAttr) {
|
||||
@ -685,24 +709,43 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
|
||||
this.pokemonGrowthRateLabelText.setVisible(true);
|
||||
this.pokemonAbilityLabelText.setVisible(true);
|
||||
this.pokemonNatureLabelText.setVisible(true);
|
||||
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
||||
|
||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species);
|
||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||
let starterIndex = -1;
|
||||
|
||||
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex);
|
||||
this.starterGens.every((g, i) => {
|
||||
const starterSpecies = this.genSpecies[g][this.starterCursors[i]];
|
||||
if (starterSpecies.speciesId === species.speciesId) {
|
||||
starterIndex = i;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (starterIndex > -1) {
|
||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.starterAttr[starterIndex]);
|
||||
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, this.starterNatures[starterIndex]);
|
||||
} else {
|
||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species);
|
||||
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||
|
||||
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, defaultNature);
|
||||
}
|
||||
} else {
|
||||
this.pokemonNumberText.setText(Utils.padInt(0, 3));
|
||||
this.pokemonNameText.setText(species ? '???' : '');
|
||||
this.pokemonGrowthRateText.setText('');
|
||||
this.pokemonGrowthRateLabelText.setVisible(false);
|
||||
this.pokemonAbilityLabelText.setVisible(false);
|
||||
this.pokemonNatureLabelText.setVisible(false);
|
||||
|
||||
this.setSpeciesDetails(species, false, 0, false, 0);
|
||||
this.setSpeciesDetails(species, false, 0, false, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean, abilityIndex: integer): void {
|
||||
setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean, abilityIndex: integer, natureIndex: integer): void {
|
||||
const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
||||
this.dexAttrCursor = 0n;
|
||||
|
||||
@ -711,8 +754,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps.female)) ? DexAttr.MALE : DexAttr.FEMALE;
|
||||
this.dexAttrCursor |= (abilityIndex !== undefined ? !abilityIndex : !(abilityIndex = oldProps.abilityIndex)) ? DexAttr.ABILITY_1 : species.ability2 && abilityIndex === 1 ? DexAttr.ABILITY_2 : DexAttr.ABILITY_HIDDEN;
|
||||
this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps.formIndex));
|
||||
if (natureIndex === undefined)
|
||||
natureIndex = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||
}
|
||||
|
||||
this.natureCursor = natureIndex;
|
||||
|
||||
this.pokemonSprite.setVisible(false);
|
||||
|
||||
if (this.assetLoadCancelled) {
|
||||
@ -724,6 +771,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
||||
if (!dexEntry.caughtAttr) {
|
||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species));
|
||||
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||
if (shiny === undefined || shiny !== props.shiny)
|
||||
shiny = props.shiny;
|
||||
if (formIndex === undefined || formIndex !== props.formIndex)
|
||||
@ -732,9 +780,27 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
female = props.female;
|
||||
if (abilityIndex === undefined || abilityIndex !== props.abilityIndex)
|
||||
abilityIndex = props.abilityIndex;
|
||||
if (natureIndex === undefined || natureIndex !== defaultNature)
|
||||
natureIndex = defaultNature;
|
||||
}
|
||||
|
||||
if (this.speciesStarterDexEntry?.caughtAttr) {
|
||||
let starterIndex = -1;
|
||||
|
||||
this.starterGens.every((g, i) => {
|
||||
const starterSpecies = this.genSpecies[g][this.starterCursors[i]];
|
||||
if (starterSpecies.speciesId === species.speciesId) {
|
||||
starterIndex = i;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (starterIndex > -1) {
|
||||
this.starterAttr[starterIndex] = this.dexAttrCursor;
|
||||
this.starterNatures[starterIndex] = this.natureCursor;
|
||||
}
|
||||
|
||||
const assetLoadCancelled = new Utils.BooleanHolder(false);
|
||||
this.assetLoadCancelled = assetLoadCancelled;
|
||||
|
||||
@ -754,6 +820,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.canCycleAbility = [ dexEntry.caughtAttr & DexAttr.ABILITY_1, dexEntry.caughtAttr & DexAttr.ABILITY_2, dexEntry.caughtAttr & DexAttr.ABILITY_HIDDEN ].filter(a => a).length > 1;
|
||||
this.canCycleForm = species.forms.filter(f => !f.formKey || f.formKey.indexOf(SpeciesFormKey.MEGA) === -1)
|
||||
.map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(a => a).length > 1;
|
||||
this.canCycleNature = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
||||
}
|
||||
|
||||
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
||||
@ -771,11 +838,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
const isHidden = ability === this.lastSpecies.abilityHidden;
|
||||
this.pokemonAbilityText.setColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD));
|
||||
this.pokemonAbilityText.setShadowColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true));
|
||||
} else
|
||||
|
||||
this.pokemonNatureText.setText(getNatureName(natureIndex as unknown as Nature, true, true));
|
||||
} else {
|
||||
this.pokemonAbilityText.setText('');
|
||||
this.pokemonNatureText.setText('');
|
||||
}
|
||||
} else {
|
||||
this.pokemonGenderText.setText('');
|
||||
this.pokemonAbilityText.setText('');
|
||||
this.pokemonNatureText.setText('');
|
||||
}
|
||||
|
||||
this.updateInstructions();
|
||||
@ -785,6 +857,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.starterGens.pop();
|
||||
this.starterCursors.pop();
|
||||
this.starterAttr.pop();
|
||||
this.starterNatures.pop();
|
||||
this.starterCursorObjs[this.starterCursors.length].setVisible(false);
|
||||
this.starterIcons[this.starterCursors.length].setTexture('pokemon_icons_0');
|
||||
this.starterIcons[this.starterCursors.length].setFrame('unknown');
|
||||
@ -832,6 +905,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
return {
|
||||
species: starterSpecies,
|
||||
dexAttr: thisObj.starterAttr[i],
|
||||
nature: thisObj.starterNatures[i] as Nature,
|
||||
pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length
|
||||
};
|
||||
}));
|
||||
|
@ -71,7 +71,7 @@ export class StatsContainer extends Phaser.GameObjects.Container {
|
||||
let label = ivs[i].toString();
|
||||
if (this.showDiff && originalIvs) {
|
||||
if (originalIvs[i] < ivs[i])
|
||||
label += ` ([color=${getGenderColor(Gender.MALE)}][shadow=${getGenderColor(Gender.MALE, true)}]+${ivs[i] - originalIvs[i]}[/shadow][/color])`;
|
||||
label += ` ([color=${getTextColor(TextStyle.SUMMARY_BLUE)}][shadow=${getTextColor(TextStyle.SUMMARY_BLUE, true)}]+${ivs[i] - originalIvs[i]}[/shadow][/color])`;
|
||||
else
|
||||
label += ' (-)';
|
||||
}
|
||||
|
@ -7,12 +7,13 @@ import { Type } from "../data/type";
|
||||
import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "./text";
|
||||
import Move, { MoveCategory } from "../data/move";
|
||||
import { getPokeballAtlasKey } from "../data/pokeball";
|
||||
import { getGenderColor, getGenderSymbol } from "../data/gender";
|
||||
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
|
||||
import { getLevelTotalExp } from "../data/exp";
|
||||
import { Stat, getStatName } from "../data/pokemon-stat";
|
||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import { StatusEffect } from "../data/status-effect";
|
||||
import { getBiomeName } from "../data/biome";
|
||||
import { Nature, getNatureStatMultiplier } from "../data/nature";
|
||||
|
||||
enum Page {
|
||||
PROFILE,
|
||||
@ -531,7 +532,7 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
});
|
||||
}
|
||||
|
||||
let memoString = `${getBBCodeFrag(`${this.pokemon.metBiome === -1 ? 'apparently ' : ''}met at Lv`, TextStyle.WINDOW)}${getBBCodeFrag(this.pokemon.metLevel.toString(), TextStyle.SUMMARY_RED)}${getBBCodeFrag(',', TextStyle.WINDOW)}\n${getBBCodeFrag(getBiomeName(this.pokemon.metBiome), TextStyle.SUMMARY_RED)}${getBBCodeFrag('.', TextStyle.WINDOW)}`;
|
||||
let memoString = `${getBBCodeFrag(Utils.toReadableString(Nature[this.pokemon.nature]), TextStyle.SUMMARY_RED)} nature,\n${getBBCodeFrag(`${this.pokemon.metBiome === -1 ? 'apparently ' : ''}met at Lv`, TextStyle.WINDOW)}${getBBCodeFrag(this.pokemon.metLevel.toString(), TextStyle.SUMMARY_RED)}${getBBCodeFrag(',', TextStyle.WINDOW)}\n${getBBCodeFrag(getBiomeName(this.pokemon.metBiome), TextStyle.SUMMARY_RED)}${getBBCodeFrag('.', TextStyle.WINDOW)}`;
|
||||
|
||||
const memoText = addBBCodeTextObject(this.scene, 7, 113, memoString, TextStyle.WINDOW);
|
||||
memoText.setOrigin(0, 0);
|
||||
@ -550,7 +551,9 @@ export default class SummaryUiHandler extends UiHandler {
|
||||
const rowIndex = s % 3;
|
||||
const colIndex = Math.floor(s / 3);
|
||||
|
||||
const statLabel = addTextObject(this.scene, 27 + 115 * colIndex, 56 + 16 * rowIndex, statName, TextStyle.SUMMARY);
|
||||
const natureStatMultiplier = getNatureStatMultiplier(this.pokemon.nature, s);
|
||||
|
||||
const statLabel = addTextObject(this.scene, 27 + 115 * colIndex, 56 + 16 * rowIndex, statName, natureStatMultiplier === 1 ? TextStyle.SUMMARY : natureStatMultiplier > 1 ? TextStyle.SUMMARY_BLUE : TextStyle.SUMMARY_PINK);
|
||||
statLabel.setOrigin(0.5, 0);
|
||||
statsContainer.add(statLabel);
|
||||
|
||||
|
@ -9,6 +9,7 @@ export enum TextStyle {
|
||||
PARTY_RED,
|
||||
SUMMARY,
|
||||
SUMMARY_RED,
|
||||
SUMMARY_BLUE,
|
||||
SUMMARY_PINK,
|
||||
SUMMARY_GOLD,
|
||||
MONEY,
|
||||
@ -129,6 +130,8 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean): string {
|
||||
case TextStyle.SUMMARY_RED:
|
||||
case TextStyle.TOOLTIP_TITLE:
|
||||
return !shadow ? '#e70808' : '#ffbd73';
|
||||
case TextStyle.SUMMARY_BLUE:
|
||||
return !shadow ? '#40c8f8' : '#006090';
|
||||
case TextStyle.SUMMARY_PINK:
|
||||
return !shadow ? '#f89890' : '#984038';
|
||||
case TextStyle.SUMMARY_GOLD:
|
||||
|
Loading…
Reference in New Issue
Block a user