diff --git a/src/constants.ts b/src/constants.ts index 17cf08aa7e2..d5dc8803255 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -107,3 +107,8 @@ export const FAKE_TITLE_LOGO_CHANCE = 10000; * Using rare candies will never increase friendship beyond this value. */ export const RARE_CANDY_FRIENDSHIP_CAP = 200; + +/** + * The maximum number of times a player can Terastallize in a single arena run + */ +export const MAX_TERAS_PER_ARENA = 1; diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 27a1052465e..8152a3c88e8 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -94,7 +94,7 @@ import i18next from "i18next"; import { applyChallenges } from "#utils/challenge-utils"; import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; import type { AbstractConstructor } from "#types/type-helpers"; -import { canTerastallize, willTerastallize } from "#utils/pokemon-utils"; +import { canSpeciesTera, willTerastallize } from "#utils/pokemon-utils"; /** * A function used to conditionally determine execution of a given {@linkcode MoveAttr}. @@ -5320,7 +5320,7 @@ export class TeraBlastTypeAttr extends VariableMoveTypeAttr { const coreType = move.type; const teraType = user.getTeraType(); /** Whether the user is allowed to tera. In the case of an enemy Pokémon, whether it *will* tera. */ - const hasTeraAccess = user.isPlayer() ? canTerastallize(user) : willTerastallize(user); + const hasTeraAccess = user.isPlayer() ? canSpeciesTera(user) : willTerastallize(user); if ( // tera type matches the move's type; no change !hasTeraAccess diff --git a/src/ui/handlers/command-ui-handler.ts b/src/ui/handlers/command-ui-handler.ts index c1a977e5a72..c5af2aa4434 100644 --- a/src/ui/handlers/command-ui-handler.ts +++ b/src/ui/handlers/command-ui-handler.ts @@ -1,3 +1,4 @@ +import { MAX_TERAS_PER_ARENA } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { getTypeRgb } from "#data/type"; @@ -198,9 +199,12 @@ export class CommandUiHandler extends UiHandler { canTera(): boolean { const activePokemon = globalScene.getField()[this.fieldIndex]; + const currentTeras = globalScene.arena.playerTerasUsed; const canTera = activePokemon.isPlayer() && canTerastallize(activePokemon); - const plannedTera = globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0; - return canTera && !plannedTera; + const plannedTera = +( + globalScene.currentBattle.preTurnCommands[0]?.command === Command.TERA && this.fieldIndex > 0 + ); + return canTera && currentTeras + plannedTera < MAX_TERAS_PER_ARENA; } toggleTeraButton() { diff --git a/src/utils/pokemon-utils.ts b/src/utils/pokemon-utils.ts index f8d0308d468..53e2da0aac3 100644 --- a/src/utils/pokemon-utils.ts +++ b/src/utils/pokemon-utils.ts @@ -1,3 +1,4 @@ +import { MAX_TERAS_PER_ARENA } from "#app/constants"; import { globalScene } from "#app/global-scene"; import { POKERUS_STARTER_COUNT, speciesStarterCosts } from "#balance/starters"; import { allSpecies } from "#data/data-lists"; @@ -136,7 +137,7 @@ export function getPokemonSpeciesForm(species: SpeciesId, formIndex: number): Po * Should really only be called with an enemy Pokémon, but will technically work with any Pokémon. * * @privateRemarks - * Assumes that Pokémon with no trainer ever tera, so this must be changed if + * Assumes that Pokémon without a trainer will never tera, so this must be changed if * a wild Pokémon is allowed to tera, e.g. for a Mystery Encounter. */ export function willTerastallize(pokemon: Pokemon): boolean { @@ -150,13 +151,22 @@ export function willTerastallize(pokemon: Pokemon): boolean { } /** - * Determine whether a player Pokémon can Terastallize + * Determine whether the Pokémon's species is tera capable, and that the player has acquired the tera orb. + * @param pokemon - The Pokémon to check + * @returns Whether + */ +export function canSpeciesTera(pokemon: Pokemon): boolean { + const hasTeraMod = globalScene.findModifier(modifier => modifier.is("TerastallizeAccessModifier")) != null; + const isBlockedForm = pokemon.isMega() || pokemon.isMax() || pokemon.hasSpecies(SpeciesId.NECROZMA, "ultra"); + return hasTeraMod && !isBlockedForm; +} + +/** + * Same as {@linkcode canSpeciesTera}, but also checks that the player has not already used their tera in the arena * @param pokemon - The Pokémon to check * @returns Whether the Pokémon can Terastallize */ export function canTerastallize(pokemon: PlayerPokemon): boolean { - const hasTeraMod = globalScene.findModifier(modifier => modifier.is("TerastallizeAccessModifier")) != null; - const isBlockedForm = pokemon.isMega() || pokemon.isMax() || pokemon.hasSpecies(SpeciesId.NECROZMA, "ultra"); - const currentTeras = globalScene.arena.playerTerasUsed === 0; - return hasTeraMod && !isBlockedForm && currentTeras; + const hasAvailableTeras = globalScene.arena.playerTerasUsed < MAX_TERAS_PER_ARENA; + return hasAvailableTeras && canSpeciesTera(pokemon); }