diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index d833aa3a3bc..ddd2cfb0c9a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -10,7 +10,7 @@ import * as Utils from "../utils"; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type"; import { getLevelTotalExp } from "../data/exp"; import { Stat } from "../data/pokemon-stat"; -import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier } from "../modifier/modifier"; +import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier } from "../modifier/modifier"; import { PokeballType } from "../data/pokeball"; import { Gender } from "../data/gender"; import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims"; @@ -707,10 +707,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { /** * Retrieves the entire set of in-battle stat stages of the {@linkcode Pokemon}. - * @returns the numeric values of the {@linkcode Pokemon}'s in-battle stat stages if available, undefined otherwise + * @returns the numeric values of the {@linkcode Pokemon}'s in-battle stat stages if available, a fresh stat stage array otherwise */ - getStatStages(): number[] | undefined { - return this.summonData ? this.summonData.statStages : undefined; + getStatStages(): number[] { + return this.summonData ? this.summonData.statStages : [ 0, 0, 0, 0, 0, 0, 0 ]; } /** @@ -817,22 +817,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.stats = [ 0, 0, 0, 0, 0, 0 ]; } + // Get and manipulate base stats const baseStats = this.getSpeciesForm(true).baseStats.slice(); if (this.isFusion()) { const fusionBaseStats = this.getFusionSpeciesForm(true).baseStats; - for (let s = 0; s < this.stats.length; s++) { + for (const s of PERMANENT_STATS) { baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2); } } else if (this.scene.gameMode.isSplicedOnly) { - for (let s = 0; s < this.stats.length; s++) { + for (const s of PERMANENT_STATS) { baseStats[s] = Math.ceil(baseStats[s] / 2); } } + this.scene.applyModifiers(BaseStatModifier, this.isPlayer(), this, baseStats); - this.scene.applyModifiers(PokemonBaseStatModifier, this.isPlayer(), this, baseStats); + // Using base stats, calculate and store stats one by one for (const s of PERMANENT_STATS) { - const baseStat = baseStats[s]; - let value = Math.floor(((2 * baseStat + this.ivs[s]) * this.level) * 0.01); + let value = Math.floor(((2 * baseStats[s] + this.ivs[s]) * this.level) * 0.01); if (s === Stat.HP) { value = value + this.level + 10; if (this.hasAbility(Abilities.WONDER_GUARD, false, true)) { diff --git a/src/locales/ca_ES/modifier-type.ts b/src/locales/ca_ES/modifier-type.ts index 551fd6359a2..66b34dc1523 100644 --- a/src/locales/ca_ES/modifier-type.ts +++ b/src/locales/ca_ES/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Increases all party members' level by {{levels}}.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Increases the holder's base {{statName}} by 10%. The higher your IVs, the higher the stack limit.", + "BaseStatBoosterModifierType": { + description: "Increases the holder's base {{stat}} by 10%. The higher your IVs, the higher the stack limit.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restores 100% HP for all Pokémon.", diff --git a/src/locales/de/modifier-type.ts b/src/locales/de/modifier-type.ts index 34616007fdd..e494d126d82 100644 --- a/src/locales/de/modifier-type.ts +++ b/src/locales/de/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Erhöht das Level aller Teammitglieder um {{levels}}.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Erhöht den {{statName}} Basiswert des Trägers um 10%. Das Stapellimit erhöht sich, je höher dein IS-Wert ist.", + "BaseStatBoosterModifierType": { + description: "Erhöht den {{stat}} Basiswert des Trägers um 10%. Das Stapellimit erhöht sich, je höher dein IS-Wert ist.", }, "AllPokemonFullHpRestoreModifierType": { description: "Stellt 100% der KP aller Pokémon her.", diff --git a/src/locales/en/modifier-type.ts b/src/locales/en/modifier-type.ts index 551fd6359a2..66b34dc1523 100644 --- a/src/locales/en/modifier-type.ts +++ b/src/locales/en/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Increases all party members' level by {{levels}}.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Increases the holder's base {{statName}} by 10%. The higher your IVs, the higher the stack limit.", + "BaseStatBoosterModifierType": { + description: "Increases the holder's base {{stat}} by 10%. The higher your IVs, the higher the stack limit.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restores 100% HP for all Pokémon.", diff --git a/src/locales/es/modifier-type.ts b/src/locales/es/modifier-type.ts index 9a73c727fd3..6e664695b47 100644 --- a/src/locales/es/modifier-type.ts +++ b/src/locales/es/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Aumenta el nivel de todos los miembros del equipo en {{levels}}.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Aumenta la est. {{statName}} base del portador en un 10%.\nCuanto mayores sean tus IVs, mayor será el límite de acumulación.", + "BaseStatBoosterModifierType": { + description: "Aumenta la est. {{stat}} base del portador en un 10%.\nCuanto mayores sean tus IVs, mayor será el límite de acumulación.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restaura el 100% de los PS de todos los Pokémon.", diff --git a/src/locales/fr/modifier-type.ts b/src/locales/fr/modifier-type.ts index 327762974c3..da6a3ed94df 100644 --- a/src/locales/fr/modifier-type.ts +++ b/src/locales/fr/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Fait monter toute l’équipe de {{levels}} niveau·x.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.", + "BaseStatBoosterModifierType": { + description: "Augmente de 10% {{stat}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restaure tous les PV de toute l’équipe.", diff --git a/src/locales/it/modifier-type.ts b/src/locales/it/modifier-type.ts index 1dd72322fed..c6a20db9e7c 100644 --- a/src/locales/it/modifier-type.ts +++ b/src/locales/it/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Aumenta i livell di tutti i Pokémon della squadra di {{levels}}.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Aumenta {{statName}} di base del possessore del 10%.", + "BaseStatBoosterModifierType": { + description: "Aumenta {{stat}} di base del possessore del 10%.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restituisce il 100% dei PS a tutti i Pokémon.", diff --git a/src/locales/ja/modifier-type.ts b/src/locales/ja/modifier-type.ts index 07857065999..08a5594d694 100644 --- a/src/locales/ja/modifier-type.ts +++ b/src/locales/ja/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "すべてのパーティメンバーのレベルを1あげる", }, - "PokemonBaseStatBoosterModifierType": { - description: "ポケモンの{{statName}}のきほんステータスを10パーセントあげる。こたいちがたかいほどスタックのげんかいもたかくなる。", + "BaseStatBoosterModifierType": { + description: "ポケモンの{{stat}}のきほんステータスを10パーセントあげる。こたいちがたかいほどスタックのげんかいもたかくなる。", }, "AllPokemonFullHpRestoreModifierType": { description: "すべてのポケモンのHPを100パーセントかいふくする", diff --git a/src/locales/ko/modifier-type.ts b/src/locales/ko/modifier-type.ts index dfdcb402b7a..682b947dee9 100644 --- a/src/locales/ko/modifier-type.ts +++ b/src/locales/ko/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "자신의 모든 포켓몬의 레벨이 {{levels}}만큼 상승한다.", }, - "PokemonBaseStatBoosterModifierType": { - description: "지니게 하면 {{statName}} 종족값을 10% 올려준다. 개체값이 높을수록 더 많이 누적시킬 수 있다.", + "BaseStatBoosterModifierType": { + description: "지니게 하면 {{stat}} 종족값을 10% 올려준다. 개체값이 높을수록 더 많이 누적시킬 수 있다.", }, "AllPokemonFullHpRestoreModifierType": { description: "자신의 포켓몬의 HP를 모두 회복한다.", diff --git a/src/locales/pt_BR/modifier-type.ts b/src/locales/pt_BR/modifier-type.ts index bc9dd84aae7..d1351dfcf5c 100644 --- a/src/locales/pt_BR/modifier-type.ts +++ b/src/locales/pt_BR/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "Aumenta em {{levels}} o nível de todos os membros da equipe.", }, - "PokemonBaseStatBoosterModifierType": { - description: "Aumenta o atributo base de {{statName}} em 10%. Quanto maior os IVs, maior o limite de aumento.", + "BaseStatBoosterModifierType": { + description: "Aumenta o atributo base de {{stat}} em 10%. Quanto maior os IVs, maior o limite de aumento.", }, "AllPokemonFullHpRestoreModifierType": { description: "Restaura totalmente os PS de todos os Pokémon.", diff --git a/src/locales/zh_CN/modifier-type.ts b/src/locales/zh_CN/modifier-type.ts index 7eff04479a3..1f45a0e397f 100644 --- a/src/locales/zh_CN/modifier-type.ts +++ b/src/locales/zh_CN/modifier-type.ts @@ -63,8 +63,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "AllPokemonLevelIncrementModifierType": { description: "使一只寶可夢的等級提升{{levels}}級。", }, - "PokemonBaseStatBoosterModifierType": { - description: "增加10%持有者的{{statName}},\n个体值越高堆叠上限越高。", + "BaseStatBoosterModifierType": { + description: "增加10%持有者的{{stat}},\n个体值越高堆叠上限越高。", }, "AllPokemonFullHpRestoreModifierType": { description: "所有宝可梦完全回复HP。", diff --git a/src/locales/zh_TW/modifier-type.ts b/src/locales/zh_TW/modifier-type.ts index 17afbec5994..e9fff5fa01d 100644 --- a/src/locales/zh_TW/modifier-type.ts +++ b/src/locales/zh_TW/modifier-type.ts @@ -63,9 +63,9 @@ export const modifierType: ModifierTypeTranslationEntries = { AllPokemonLevelIncrementModifierType: { description: "Increases all party members' level by {{levels}}.", }, - PokemonBaseStatBoosterModifierType: { + BaseStatBoosterModifierType: { description: - "增加持有者的{{statName}}10%,個體值越高堆疊\n上限越高。", + "增加持有者的{{stat}}10%,個體值越高堆疊\n上限越高。", }, AllPokemonFullHpRestoreModifierType: { description: "所有寶可夢完全恢復HP。", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index ee34b1b4316..93ebee3d7a8 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -3,7 +3,6 @@ import { AttackMove, allMoves, selfStatLowerMoves } from "../data/move"; import { MAX_PER_TYPE_POKEBALLS, PokeballType, getPokeballCatchMultiplier, getPokeballName } from "../data/pokeball"; import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "../field/pokemon"; import { EvolutionItem, pokemonEvolutions } from "../data/pokemon-evolutions"; -import { Stat, getStatName } from "../data/pokemon-stat"; import { tmPoolTiers, tmSpecies } from "../data/tms"; import { Type } from "../data/type"; import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "../ui/party-ui-handler"; @@ -27,7 +26,7 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; -import { TEMP_BATTLE_STATS, TempBattleStat } from "#app/enums/stat"; +import { PermanentStat, TEMP_BATTLE_STATS, TempBattleStat, Stat } from "#app/enums/stat"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -593,40 +592,24 @@ export class AllPokemonLevelIncrementModifierType extends ModifierType { } } -function getBaseStatBoosterItemName(stat: Stat) { - switch (stat) { - case Stat.HP: - return "HP Up"; - case Stat.ATK: - return "Protein"; - case Stat.DEF: - return "Iron"; - case Stat.SPATK: - return "Calcium"; - case Stat.SPDEF: - return "Zinc"; - case Stat.SPD: - return "Carbos"; - } -} +export class BaseStatBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType { + private stat: PermanentStat; + private key: string; -export class PokemonBaseStatBoosterModifierType extends PokemonHeldItemModifierType implements GeneratedPersistentModifierType { - private localeName: string; - private stat: Stat; + constructor(stat: PermanentStat) { + const key = BaseStatBoosterModifierTypeGenerator.items[stat]; + super("", key, (_type, args) => new Modifiers.BaseStatModifier(this, (args[0] as Pokemon).id, this.stat)); - constructor(localeName: string, stat: Stat) { - super("", localeName.replace(/[ \-]/g, "_").toLowerCase(), (_type, args) => new Modifiers.PokemonBaseStatModifier(this, (args[0] as Pokemon).id, this.stat)); - - this.localeName = localeName; this.stat = stat; + this.key = key; } get name(): string { - return i18next.t(`modifierType:BaseStatBoosterItem.${this.localeName.replace(/[ \-]/g, "_").toLowerCase()}`); + return i18next.t(`modifierType:BaseStatBoosterItem.${this.key}`); } - getDescription(scene: BattleScene): string { - return i18next.t("modifierType:ModifierType.PokemonBaseStatBoosterModifierType.description", { statName: getStatName(this.stat) }); + getDescription(_scene: BattleScene): string { + return i18next.t("modifierType:ModifierType.BaseStatBoosterModifierType.description", { stat: i18next.t(`pokemonInfo:Stat.${Stat[this.stat]}`) }); } getPregenArgs(): any[] { @@ -904,6 +887,27 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { } } +class BaseStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { + public static readonly items: Record = { + [Stat.HP]: "hp_up", + [Stat.ATK]: "protein", + [Stat.DEF]: "iron", + [Stat.SPATK]: "calcium", + [Stat.SPDEF]: "zinc", + [Stat.SPD]: "carbos" + }; + + constructor() { + super((_party: Pokemon[], pregenArgs?: any[]) => { + if (pregenArgs) { + return new BaseStatBoosterModifierType(pregenArgs[0]); + } + const randStat: PermanentStat = Utils.randSeedInt(Stat.SPD + 1); + return new BaseStatBoosterModifierType(randStat); + }); + } +} + class TempStatStageBoosterModifierTypeGenerator extends ModifierTypeGenerator { public static readonly items: Record = { [Stat.ATK]: "x_attack", @@ -1304,14 +1308,7 @@ export const modifierTypes = { } }("modifierType:ModifierType.DIRE_HIT", "dire_hit", (type, _args) => new Modifiers.TempCritBoosterModifier(type)), - BASE_STAT_BOOSTER: () => new ModifierTypeGenerator((party: Pokemon[], pregenArgs?: any[]) => { - if (pregenArgs) { - const stat = pregenArgs[0] as Stat; - return new PokemonBaseStatBoosterModifierType(getBaseStatBoosterItemName(stat)!, stat); // TODO: Stat - } - const randStat = Utils.randSeedInt(6) as Stat; - return new PokemonBaseStatBoosterModifierType(getBaseStatBoosterItemName(randStat)!, randStat); // TODO: Stat - }), + BASE_STAT_BOOSTER: () => new BaseStatBoosterModifierTypeGenerator(), ATTACK_TYPE_BOOSTER: () => new AttackTypeBoosterModifierTypeGenerator(), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 5aea88bb21b..2fc535fd37d 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -23,7 +23,7 @@ import Overrides from "#app/overrides"; import { ModifierType, modifierTypes } from "./modifier-type"; import { Command } from "#app/ui/command-ui-handler.js"; import { Species } from "#enums/species"; -import { BATTLE_STATS, TEMP_BATTLE_STATS, TempBattleStat } from "#app/enums/stat"; +import { BATTLE_STATS, PermanentStat, TEMP_BATTLE_STATS, TempBattleStat } from "#app/enums/stat"; // TODO: Add Type import i18next from "i18next"; import { allMoves } from "#app/data/move.js"; @@ -708,24 +708,30 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier { } } -export class PokemonBaseStatModifier extends PokemonHeldItemModifier { - protected stat: Stat; +/** + * Modifier used for held items, specifically vitamins like Carbos, Hp Up, etc., that + * increase the value of a given {@linkcode PermanentStat}. + * @extends LapsingPersistentModifier + * @see {@linkcode apply} + */ +export class BaseStatModifier extends PokemonHeldItemModifier { + protected stat: PermanentStat; readonly isTransferrable: boolean = false; - constructor(type: ModifierTypes.PokemonBaseStatBoosterModifierType, pokemonId: integer, stat: Stat, stackCount?: integer) { + constructor(type: ModifierType, pokemonId: integer, stat: PermanentStat, stackCount?: integer) { super(type, pokemonId, stackCount); this.stat = stat; } matchType(modifier: Modifier): boolean { - if (modifier instanceof PokemonBaseStatModifier) { - return (modifier as PokemonBaseStatModifier).stat === this.stat; + if (modifier instanceof BaseStatModifier) { + return (modifier as BaseStatModifier).stat === this.stat; } return false; } clone(): PersistentModifier { - return new PokemonBaseStatModifier(this.type as ModifierTypes.PokemonBaseStatBoosterModifierType, this.pokemonId, this.stat, this.stackCount); + return new BaseStatModifier(this.type, this.pokemonId, this.stat, this.stackCount); } getArgs(): any[] { @@ -733,12 +739,12 @@ export class PokemonBaseStatModifier extends PokemonHeldItemModifier { } shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array; + return super.shouldApply(args) && args.length === 2 && Array.isArray(args[1]); } apply(args: any[]): boolean { - args[1][this.stat] = Math.min(Math.floor(args[1][this.stat] * (1 + this.getStackCount() * 0.1)), 999999); - + const baseStats = args[1] as number[]; + baseStats[this.stat] = Math.floor(baseStats[this.stat] * (1 + this.getStackCount() * 0.1)); return true; } diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index c091d4a3aa5..ceee07eda01 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -650,9 +650,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastLevel = pokemon.level; } - const battleStats = pokemon.summonData - ? pokemon.summonData.statStages // TODO: BattleStats - : this.battleStatOrder.map(() => 0); + const battleStats = pokemon.getStatStages(); const battleStatsStr = battleStats.join(""); if (this.lastBattleStats !== battleStatsStr) { diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 3a9b3463ef1..2f9c9a9737f 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -6,7 +6,7 @@ import { Command } from "./command-ui-handler"; import MessageUiHandler from "./message-ui-handler"; import { Mode } from "./ui"; import * as Utils from "../utils"; -import { PokemonBaseStatModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier"; +import { BaseStatModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier"; import { allMoves, ForceSwitchOutAttr } from "../data/move"; import { getGenderColor, getGenderSymbol } from "../data/gender"; import { StatusEffect } from "../data/status-effect"; @@ -996,8 +996,8 @@ export default class PartyUiHandler extends MessageUiHandler { if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && this.transferQuantitiesMax[option] > 1) { const itemModifier = itemModifiers[option]; - /** Not sure why getMaxHeldItemCount had an error, but it only checks the Pokemon parameter if the modifier is PokemonBaseStatModifier */ - if (itemModifier === undefined || itemModifier instanceof PokemonBaseStatModifier) { + /** Not sure why getMaxHeldItemCount had an error, but it only checks the Pokemon parameter if the modifier is BaseStatModifier */ + if (itemModifier === undefined || itemModifier instanceof BaseStatModifier) { continue; }