diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index 86543a082a7..16aaa460597 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -10,7 +10,7 @@ import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { TimeOfDay } from "#enums/time-of-day"; -import { DamageMoneyRewardModifier, EvoTrackerModifier, ExtraModifierModifier, MoneyMultiplierModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; +import { DamageMoneyRewardModifier, EvoTrackerModifier, EvoTrackerMoveUseModifier, ExtraModifierModifier, MoneyMultiplierModifier, PersistentModifier, TempExtraModifierModifier } from "#app/modifier/modifier"; import { SpeciesFormKey } from "#enums/species-form-key"; import { speciesStarterCosts } from "./starters"; import i18next from "i18next"; @@ -241,11 +241,33 @@ export class SpeciesEvolutionCondition { case EvoCondKey.SPECIES_CAUGHT: return !!globalScene.gameData.dexData[this.data.speciesCaught!].caughtAttr; case EvoCondKey.MOVE_USE_COUNT: + return pokemon.getHeldItems().some(m => + m instanceof EvoTrackerMoveUseModifier && + m.shouldApply(pokemon, this.data.move!) && + m.getStackCount() >= this.data.evoCount!); case EvoCondKey.RECOIL_DAMAGE_COUNT: return pokemon.evoCounter >= this.data.evoCount!; } }); } + + public postEvolve(pokemon: Pokemon): void { + const keys = Array.isArray(this.data.key) ? this.data.key : [this.data.key]; + keys.map(cond => { + let modifier: PersistentModifier | undefined; + switch (cond) { + case EvoCondKey.EVO_TREASURE_TRACKER: + modifier = globalScene.findModifier(m => m instanceof EvoTrackerModifier && m.pokemonId === pokemon.id); + break; + case EvoCondKey.MOVE_USE_COUNT: + modifier = globalScene.findModifier(m => m instanceof EvoTrackerMoveUseModifier && m.shouldApply(pokemon, this.data.move!)); + break; + } + if (!isNullOrUndefined(modifier)) { + globalScene.removeModifier(modifier); + } + }); + } } export function validateShedinjaEvo(): boolean { @@ -324,6 +346,12 @@ export class SpeciesFormEvolution { ); } + public postEvolve(pokemon: Pokemon): void { + if (!isNullOrUndefined(this.condition)) { + this.condition.postEvolve(pokemon); + } + } + public get evoItem(): EvolutionItem { return this.item ?? EvolutionItem.NONE; } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 44371f94027..ca241f46c4f 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -98,6 +98,7 @@ import { TempExtraModifierModifier, CriticalCatchChanceBoosterModifier, FieldEffectModifier, + EvoTrackerMoveUseModifier, } from "#app/modifier/modifier"; import { ModifierTier } from "#app/modifier/modifier-tier"; import Overrides from "#app/overrides"; @@ -1898,6 +1899,20 @@ export const modifierTypes = { "relic_gold", (type, args) => new EvoTrackerModifier(type, (args[0] as Pokemon).id, Species.GIMMIGHOUL, 10, (args[1] as number ?? 1)), ), + + EVOLUTION_TRACKER_PRIMEAPE: () => + new PokemonHeldItemModifierType( + "modifierType:ModifierType.EVOLUTION_TRACKER_PRIMEAPE", + "tm_ghost", + (type, args) => new EvoTrackerMoveUseModifier(type, (args[0] as Pokemon).id, Species.PRIMEAPE, Moves.RAGE_FIST, 10) + ), + + EVOLUTION_TRACKER_STANTLER: () => + new PokemonHeldItemModifierType( + "modifierType:ModifierType.EVOLUTION_TRACKER_STANTLER", + "tm_psychic", + (type, args) => new EvoTrackerMoveUseModifier(type, (args[0] as Pokemon).id, Species.STANTLER, Moves.PSYSHIELD_BASH, 10) + ), MEGA_BRACELET: () => new ModifierType( diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index a5254e93c89..7ab0014e1aa 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -918,15 +918,64 @@ export class EvoTrackerModifier extends PokemonHeldItemModifier { } getMaxHeldItemCount(pokemon: Pokemon): number { - this.stackCount = - pokemon.evoCounter + - pokemon.getHeldItems().filter(m => m instanceof DamageMoneyRewardModifier).length + - globalScene.findModifiers( - m => - m instanceof MoneyMultiplierModifier || - m instanceof ExtraModifierModifier || - m instanceof TempExtraModifierModifier, - ).length; + return 999; + } +} + +export class EvoTrackerMoveUseModifier extends PokemonHeldItemModifier { + protected species: Species; + protected move: Moves; + protected required: number; + public isTransferable = false; + + constructor(type: ModifierType, pokemonId: number, species: Species, move: Moves, required: number, stackCount?: number) { + super(type, pokemonId, stackCount); + this.species = species; + this.move = move; + this.required = required; + } + + matchType(modifier: Modifier): boolean { + return ( + modifier instanceof EvoTrackerMoveUseModifier && + modifier.species === this.species && + modifier.move === this.move && + modifier.required === this.required + ); + } + + clone(): PersistentModifier { + return new EvoTrackerMoveUseModifier(this.type, this.pokemonId, this.species, this.move, this.required, this.stackCount); + } + + getArgs(): any[] { + return super.getArgs().concat([this.species, this.move, this.required]); + } + + /** + * Applies the {@linkcode EvoTrackerMoveUseModifier} + * @returns always `true` + */ + override apply(): boolean { + return true; + } + + getIconStackText(virtual?: boolean): Phaser.GameObjects.BitmapText | null { + const text = globalScene.add.bitmapText(10, 15, "item-count", this.getStackCount().toString(), 11); + text.letterSpacing = -0.5; + if (this.getStackCount() >= this.required) { + text.setTint(0xf89890); + } + text.setOrigin(0, 0); + + return text; + } + + override shouldApply(pokemon?: Pokemon, move?: Moves): boolean { + return move === this.move; + } + + getMaxHeldItemCount(pokemon: Pokemon): number { return 999; } } diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index 7b013555f40..badad2426dc 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -343,6 +343,7 @@ export class EvolutionPhase extends Phase { this.evolutionHandler.canCancel = false; this.pokemon.evolve(this.evolution, this.pokemon.species).then(() => { + this.evolution?.postEvolve(this.pokemon); const learnSituation: LearnMoveSituation = this.fusionSpeciesEvolved ? LearnMoveSituation.EVOLUTION_FUSED : this.pokemon.fusionSpecies diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 3f0835536dc..dd2d1bba6d4 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -57,6 +57,7 @@ import { DamageMoneyRewardModifier, EnemyAttackStatusEffectChanceModifier, EnemyEndureChanceModifier, + EvoTrackerMoveUseModifier, FlinchChanceModifier, HitHealModifier, PokemonMultiHitModifier, @@ -79,6 +80,7 @@ import { isFieldTargeted } from "#app/data/moves/move-utils"; import { FaintPhase } from "./faint-phase"; import { DamageAchv } from "#app/system/achv"; import { Species } from "#enums/species"; +import { modifierTypes } from "#app/modifier/modifier-type"; type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier]; @@ -793,14 +795,14 @@ export class MoveEffectPhase extends PokemonPhase { // Increment evo counter for Primeape and Stantler if ( + (user.isPlayer() && ((user.hasSpecies(Species.PRIMEAPE) && this.move.id === Moves.RAGE_FIST) || - (user.hasSpecies(Species.STANTLER) && this.move.id === Moves.PSYSHIELD_BASH))) { - if (isNullOrUndefined(user.evoCounter)) { - user.evoCounter = 1; - } - else { - user.evoCounter++; - } + (user.hasSpecies(Species.STANTLER) && this.move.id === Moves.PSYSHIELD_BASH)))) { + const modifier = (this.move.id === Moves.RAGE_FIST ? + modifierTypes.EVOLUTION_TRACKER_PRIMEAPE().withIdFromFunc(modifierTypes.EVOLUTION_TRACKER_PRIMEAPE) : + modifierTypes.EVOLUTION_TRACKER_STANTLER().withIdFromFunc(modifierTypes.EVOLUTION_TRACKER_STANTLER)) + .newModifier(user) as EvoTrackerMoveUseModifier; + globalScene.addModifier(modifier); } // Multi-hit check for Wimp Out/Emergency Exit