diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index 298cf2d0719..d5f8ff18870 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -11,11 +11,11 @@ import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { SpeciesFormKey } from "#enums/species-form-key"; import { TimeOfDay } from "#enums/time-of-day"; -import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifier, SpeciesStatBoosterModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; -import type { SpeciesStatBoosterModifierType } from "#app/modifier/modifier-type"; import { speciesStarterCosts } from "./starters"; import i18next from "i18next"; import { initI18n } from "#app/plugins/i18n"; +import { allHeldItems } from "#app/items/all-held-items"; +import { HeldItemId } from "#enums/held-item-id"; export enum SpeciesWildEvolutionDelay { NONE, @@ -274,10 +274,7 @@ class MoveTypeEvolutionCondition extends SpeciesEvolutionCondition { class TreasureEvolutionCondition extends SpeciesEvolutionCondition { constructor() { - super(p => p.evoCounter - + p.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length - + globalScene.findModifiers(m => m instanceof MoneyMultiplierModifier - || m instanceof ExtraModifierModifier || m instanceof TempExtraModifierModifier).length > 9); + super(p => allHeldItems[HeldItemId.GIMMIGHOUL_EVO_TRACKER].getStackCount(p) > 9); this.description = i18next.t("pokemonEvolutions:treasure"); } } @@ -1794,8 +1791,8 @@ export const pokemonEvolutions: PokemonEvolutions = { ], [SpeciesId.CLAMPERL]: [ // TODO: Change the SpeciesEvolutionConditions here to use a bespoke HeldItemEvolutionCondition after the modifier rework - new SpeciesEvolution(SpeciesId.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.getHeldItems().some(m => m instanceof SpeciesStatBoosterModifier && (m.type as SpeciesStatBoosterModifierType).key === "DEEP_SEA_TOOTH")), SpeciesWildEvolutionDelay.VERY_LONG), - new SpeciesEvolution(SpeciesId.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.getHeldItems().some(m => m instanceof SpeciesStatBoosterModifier && (m.type as SpeciesStatBoosterModifierType).key === "DEEP_SEA_SCALE")), SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(SpeciesId.HUNTAIL, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.heldItemManager.hasItem(HeldItemId.DEEP_SEA_TOOTH)), SpeciesWildEvolutionDelay.VERY_LONG), + new SpeciesEvolution(SpeciesId.GOREBYSS, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => p.heldItemManager.hasItem(HeldItemId.DEEP_SEA_SCALE)), SpeciesWildEvolutionDelay.VERY_LONG) ], [SpeciesId.BOLDORE]: [ new SpeciesEvolution(SpeciesId.GIGALITH, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG) diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index e8a3db46cff..6d7366ea79e 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -28,7 +28,6 @@ import { showEncounterText, } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getPokemonNameWithAffix } from "#app/messages"; -import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; import { Gender } from "#app/data/gender"; import type { PermanentStat } from "#enums/stat"; @@ -37,6 +36,7 @@ import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { AbilityId } from "#enums/ability-id"; import type { PokeballType } from "#enums/pokeball"; import { StatusEffect } from "#enums/status-effect"; +import type { HeldItemId } from "#enums/held-item-id"; /** Will give +1 level every 10 waves */ export const STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER = 1; @@ -423,6 +423,13 @@ export async function applyModifierTypeToPlayerPokemon( globalScene.addModifier(modifier, false, false, false, true); } +export function applyHeldItemWithFallback(pokemon: Pokemon, item: HeldItemId, fallbackItem?: HeldItemId) { + const added = pokemon.heldItemManager.add(item); + if (!added && fallbackItem) { + pokemon.heldItemManager.add(fallbackItem); + } +} + /** * Alternative to using AttemptCapturePhase * Assumes player sprite is visible on the screen (this is intended for non-combat uses) diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index f34a589e893..b21bf78a801 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -25,6 +25,7 @@ import { type SpeciesFormChangeTrigger, SpeciesFormChangeWeatherTrigger, } from "./pokemon-forms/form-change-triggers"; +import i18next from "i18next"; export function formChangeItemName(id: FormChangeItem) { return i18next.t(`modifierType:FormChangeItem.${FormChangeItem[id]}`); diff --git a/src/field/pokemon-held-item-manager.ts b/src/field/pokemon-held-item-manager.ts index 6c66c219369..340347317d9 100644 --- a/src/field/pokemon-held-item-manager.ts +++ b/src/field/pokemon-held-item-manager.ts @@ -8,12 +8,12 @@ type HELD_ITEM_DATA = BASE_STAT_TOTAL_DATA | BASE_STAT_FLAT_DATA; interface HeldItemProperties { stack: number; - disabled: boolean; + disabled?: boolean; cooldown?: number; data?: HELD_ITEM_DATA; } -type HeldItemPropertyMap = { +export type HeldItemPropertyMap = { [key in HeldItemId]?: HeldItemProperties; }; @@ -21,7 +21,7 @@ interface FormChangeItemProperties { active: boolean; } -type FormChangeItemPropertyMap = { +export type FormChangeItemPropertyMap = { [key in FormChangeItem]?: FormChangeItemProperties; }; @@ -73,6 +73,10 @@ export class PokemonItemManager { return item ? item.stack : 0; } + overrideItems(newItems: HeldItemPropertyMap) { + this.heldItems = newItems; + } + add(itemType: HeldItemId, addStack = 1, data?: HELD_ITEM_DATA): boolean { const maxStack = allHeldItems[itemType].getMaxStackCount(); const item = this.heldItems[itemType]; diff --git a/src/items/held-items/bypass-speed-chance.ts b/src/items/held-items/bypass-speed-chance.ts index 40fc65593ff..6c1b2aba73e 100644 --- a/src/items/held-items/bypass-speed-chance.ts +++ b/src/items/held-items/bypass-speed-chance.ts @@ -4,7 +4,7 @@ import type { BooleanHolder } from "#app/utils/common"; import { globalScene } from "#app/global-scene"; import i18next from "i18next"; import { getPokemonNameWithAffix } from "#app/messages"; -import { Command } from "#app/ui/command-ui-handler"; +import { Command } from "#enums/command"; export interface BYPASS_SPEED_CHANCE_PARAMS { /** The pokemon with the item */ diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 679b79cd4b0..2ca6f1d826b 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -46,7 +46,6 @@ import { MoneyRewardModifier, MultipleParticipantExpBonusModifier, PokemonAllMovePpRestoreModifier, - PokemonFormChangeItemModifier, type PokemonHeldItemModifier, PokemonHpRestoreModifier, PokemonLevelIncrementModifier, @@ -1099,8 +1098,8 @@ export class FormChangeItemReward extends PokemonModifierType { constructor(formChangeItem: FormChangeItem) { super( "", - FormChangeItem[formChangeItem].toLowerCase(), - (_type, args) => new PokemonFormChangeItemModifier(this, (args[0] as PlayerPokemon).id, formChangeItem, true), + "", + () => null, (pokemon: PlayerPokemon) => { // Make sure the Pokemon has alternate forms if ( diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 5ebaf1bf6df..9b5932bdbda 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1,8 +1,6 @@ import { FusionSpeciesFormEvolution, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { getLevelTotalExp } from "#app/data/exp"; import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; -import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers"; -import type { FormChangeItem } from "#enums/form-change-item"; import { getStatusEffectHealText } from "#app/data/status-effect"; import type Pokemon from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon"; @@ -10,7 +8,6 @@ import { getPokemonNameWithAffix } from "#app/messages"; import Overrides from "#app/overrides"; import { LearnMoveType } from "#enums/learn-move-type"; import type { VoucherType } from "#app/system/voucher"; -import { Command } from "#enums/command"; import { addTextObject, TextStyle } from "#app/ui/text"; import { type BooleanHolder, @@ -31,7 +28,6 @@ import i18next from "i18next"; import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, - type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type TerastallizeModifierType, @@ -546,107 +542,6 @@ export class TerastallizeAccessModifier extends PersistentModifier { } } -export abstract class PokemonHeldItemModifier extends PersistentModifier { - /** The ID of the {@linkcode Pokemon} that this item belongs to. */ - public pokemonId: number; - /** Whether this item can be transfered to or stolen by another Pokemon. */ - public isTransferable = true; - - constructor(type: ModifierType, pokemonId: number, stackCount?: number) { - super(type, stackCount); - - this.pokemonId = pokemonId; - } - - abstract matchType(_modifier: Modifier): boolean; - - match(modifier: Modifier) { - return this.matchType(modifier) && (modifier as PokemonHeldItemModifier).pokemonId === this.pokemonId; - } - - getArgs(): any[] { - return [this.pokemonId]; - } - - /** - * Applies the {@linkcode PokemonHeldItemModifier} to the given {@linkcode Pokemon}. - * @param pokemon The {@linkcode Pokemon} that holds the held item - * @param args additional parameters - */ - abstract override apply(pokemon: Pokemon, ...args: unknown[]): boolean; - - /** - * Checks if {@linkcode PokemonHeldItemModifier} should be applied. - * @param pokemon The {@linkcode Pokemon} that holds the item - * @param _args N/A - * @returns if {@linkcode PokemonHeldItemModifier} should be applied - */ - override shouldApply(pokemon?: Pokemon, ..._args: unknown[]): boolean { - return !!pokemon && (this.pokemonId === -1 || pokemon.id === this.pokemonId); - } - - isIconVisible(): boolean { - return !!this.getPokemon()?.isOnField(); - } - - getIcon(forSummary?: boolean): Phaser.GameObjects.Container { - const container = !forSummary ? globalScene.add.container(0, 0) : super.getIcon(); - - if (!forSummary) { - const pokemon = this.getPokemon(); - if (pokemon) { - const pokemonIcon = globalScene.addPokemonIcon(pokemon, -2, 10, 0, 0.5, undefined, true); - container.add(pokemonIcon); - container.setName(pokemon.id.toString()); - } - - const item = globalScene.add.sprite(16, this.virtualStackCount ? 8 : 16, "items"); - item.setScale(0.5); - item.setOrigin(0, 0.5); - item.setTexture("items", this.type.getIcon()); - container.add(item); - - const stackText = this.getIconStackText(); - if (stackText) { - container.add(stackText); - } - - const virtualStackText = this.getIconStackText(true); - if (virtualStackText) { - container.add(virtualStackText); - } - } else { - container.setScale(0.5); - } - - return container; - } - - getPokemon(): Pokemon | undefined { - return this.pokemonId ? (globalScene.getPokemonById(this.pokemonId) ?? undefined) : undefined; - } - - getScoreMultiplier(): number { - return 1; - } - - getMaxStackCount(forThreshold?: boolean): number { - const pokemon = this.getPokemon(); - if (!pokemon) { - return 0; - } - if (pokemon.isPlayer() && forThreshold) { - return globalScene - .getPlayerParty() - .map(p => this.getMaxHeldItemCount(p)) - .reduce((stackCount: number, maxStackCount: number) => Math.max(stackCount, maxStackCount), 0); - } - return this.getMaxHeldItemCount(pokemon); - } - - abstract getMaxHeldItemCount(pokemon?: Pokemon): number; -} - export class LevelIncrementBoosterModifier extends PersistentModifier { match(modifier: Modifier) { return modifier instanceof LevelIncrementBoosterModifier; @@ -1254,69 +1149,6 @@ export class ExpBalanceModifier extends PersistentModifier { } } -export class PokemonFormChangeItemModifier extends PokemonHeldItemModifier { - public override type: FormChangeItemModifierType; - public formChangeItem: FormChangeItem; - public active: boolean; - public isTransferable = false; - - constructor( - type: FormChangeItemModifierType, - pokemonId: number, - formChangeItem: FormChangeItem, - active: boolean, - stackCount?: number, - ) { - super(type, pokemonId, stackCount); - this.formChangeItem = formChangeItem; - this.active = active; - } - - matchType(modifier: Modifier): boolean { - return modifier instanceof PokemonFormChangeItemModifier && modifier.formChangeItem === this.formChangeItem; - } - - clone(): PersistentModifier { - return new PokemonFormChangeItemModifier( - this.type, - this.pokemonId, - this.formChangeItem, - this.active, - this.stackCount, - ); - } - - getArgs(): any[] { - return super.getArgs().concat(this.formChangeItem, this.active); - } - - /** - * Applies {@linkcode PokemonFormChangeItemModifier} - * @param pokemon The {@linkcode Pokemon} to apply the form change item to - * @param active `true` if the form change item is active - * @returns `true` if the form change item was applied - */ - override apply(pokemon: Pokemon, active: boolean): boolean { - const switchActive = this.active && !active; - - if (switchActive) { - this.active = false; - } - - const ret = globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeItemTrigger); - - if (switchActive) { - this.active = true; - } - - return ret; - } - - getMaxHeldItemCount(_pokemon: Pokemon): number { - return 1; - } -} - export class MoneyRewardModifier extends ConsumableModifier { private moneyMultiplier: number; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 03cca175b6f..772d32d6c46 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -14,7 +14,7 @@ import { StatusEffect } from "#enums/status-effect"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { addWindow } from "#app/ui/ui-theme"; -import { SpeciesFormChangeItemTrigger, formChangeItemName } from "#app/data/pokemon-forms/form-change-triggers"; +import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers"; import { FormChangeItem } from "#enums/form-change-item"; import { getVariantTint } from "#app/sprites/variant"; import { Button } from "#enums/buttons"; @@ -29,6 +29,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import type { CommandPhase } from "#app/phases/command-phase"; import { globalScene } from "#app/global-scene"; import { HeldItemId } from "#enums/held-item-id"; +import { formChangeItemName } from "#app/data/pokemon-forms"; const defaultMessage = i18next.t("partyUiHandler:choosePokemon");