Move species form change triggers to own file

Reduces circ imports to 291
This commit is contained in:
Sirz Benjie 2025-06-08 11:36:35 -05:00
parent befbfeef6d
commit e2b6b577ac
No known key found for this signature in database
GPG Key ID: 4A524B4D196C759E
26 changed files with 401 additions and 377 deletions

View File

@ -103,12 +103,11 @@ import type UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import { addUiThemeOverrides } from "#app/ui/ui-theme"; import { addUiThemeOverrides } from "#app/ui/ui-theme";
import type PokemonData from "#app/system/pokemon-data"; import type PokemonData from "#app/system/pokemon-data";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import type { SpeciesFormChange, SpeciesFormChangeTrigger } from "#app/data/pokemon-forms"; import type { SpeciesFormChange } from "#app/data/pokemon-forms";
import { import type { SpeciesFormChangeTrigger } from "./data/pokemon-forms/form-change-triggers";
pokemonFormChanges, import { pokemonFormChanges } from "#app/data/pokemon-forms";
SpeciesFormChangeManualTrigger, import { SpeciesFormChangeTimeOfDayTrigger } from "./data/pokemon-forms/form-change-triggers";
SpeciesFormChangeTimeOfDayTrigger, import { SpeciesFormChangeManualTrigger } from "./data/pokemon-forms/form-change-triggers";
} from "#app/data/pokemon-forms";
import { FormChangeItem } from "#enums/form-change-item"; import { FormChangeItem } from "#enums/form-change-item";
import { getTypeRgb } from "#app/data/type"; import { getTypeRgb } from "#app/data/type";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";

View File

@ -40,10 +40,10 @@ import { ArenaTagSide } from "#enums/arena-tag-side";
import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain";
import { import {
SpeciesFormChangeAbilityTrigger,
SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeRevertWeatherFormTrigger,
SpeciesFormChangeWeatherTrigger, SpeciesFormChangeWeatherTrigger,
} from "#app/data/pokemon-forms"; } from "../pokemon-forms/form-change-triggers";
import { SpeciesFormChangeAbilityTrigger } from "../pokemon-forms/form-change-triggers";
import i18next from "i18next"; import i18next from "i18next";
import { Command } from "#enums/command"; import { Command } from "#enums/command";
import { BerryModifierType } from "#app/modifier/modifier-type"; import { BerryModifierType } from "#app/modifier/modifier-type";

View File

@ -21,7 +21,7 @@ import {
import { allMoves } from "./data-lists"; import { allMoves } from "./data-lists";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeAbilityTrigger } from "./pokemon-forms/form-change-triggers";
import { getStatusEffectHealText } from "#app/data/status-effect"; import { getStatusEffectHealText } from "#app/data/status-effect";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";

View File

@ -107,7 +107,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { SwitchPhase } from "#app/phases/switch-phase"; import { SwitchPhase } from "#app/phases/switch-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase"; import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { SpeciesFormChangeRevertWeatherFormTrigger } from "../pokemon-forms"; import { SpeciesFormChangeRevertWeatherFormTrigger } from "../pokemon-forms/form-change-triggers";
import type { GameMode } from "#app/game-mode"; import type { GameMode } from "#app/game-mode";
import { applyChallenges } from "../challenge"; import { applyChallenges } from "../challenge";
import { ChallengeType } from "#enums/challenge-type"; import { ChallengeType } from "#enums/challenge-type";

View File

@ -25,7 +25,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
import { addPokeballOpenParticles } from "#app/field/anims"; import { addPokeballOpenParticles } from "#app/field/anims";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";

View File

@ -23,7 +23,7 @@ import { Nature } from "#enums/nature";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability"; import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability";
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";

View File

@ -2,7 +2,8 @@ import { globalScene } from "#app/global-scene";
import { allAbilities } from "../data-lists"; import { allAbilities } from "../data-lists";
import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { EvolutionItem, pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { pokemonFormChanges, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; import { pokemonFormChanges } from "#app/data/pokemon-forms";
import { SpeciesFormChangeItemTrigger } from "../pokemon-forms/form-change-triggers";
import { FormChangeItem } from "#enums/form-change-item"; import { FormChangeItem } from "#enums/form-change-item";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";

View File

@ -1,20 +1,30 @@
import { PokemonFormChangeItemModifier } from "../modifier/modifier";
import type Pokemon from "../field/pokemon"; import type Pokemon from "../field/pokemon";
import { StatusEffect } from "#enums/status-effect";
import { allMoves } from "./data-lists"; import { allMoves } from "./data-lists";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import type { Constructor, nil } from "#app/utils/common"; import type { Constructor, nil } from "#app/utils/common";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import type { TimeOfDay } from "#enums/time-of-day";
import { getPokemonNameWithAffix } from "#app/messages";
import i18next from "i18next";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { Challenges } from "#app/enums/challenges";
import { SpeciesFormKey } from "#enums/species-form-key"; import { SpeciesFormKey } from "#enums/species-form-key";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { FormChangeItem } from "#enums/form-change-item"; import { FormChangeItem } from "#enums/form-change-item";
import {
MeloettaFormChangePostMoveTrigger,
SpeciesDefaultFormMatchTrigger,
SpeciesFormChangeAbilityTrigger,
SpeciesFormChangeActiveTrigger,
SpeciesFormChangeCompoundTrigger,
SpeciesFormChangeItemTrigger,
SpeciesFormChangeLapseTeraTrigger,
SpeciesFormChangeManualTrigger,
SpeciesFormChangeMoveLearnedTrigger,
SpeciesFormChangePreMoveTrigger,
SpeciesFormChangeRevertWeatherFormTrigger,
SpeciesFormChangeTeraTrigger,
type SpeciesFormChangeTrigger,
SpeciesFormChangeWeatherTrigger,
} from "./pokemon-forms/form-change-triggers";
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean; export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void; export type SpeciesFormChangeConditionEnforceFunc = (p: Pokemon) => void;
@ -95,347 +105,6 @@ export class SpeciesFormChangeCondition {
} }
} }
export abstract class SpeciesFormChangeTrigger {
public description = "";
canChange(_pokemon: Pokemon): boolean {
return true;
}
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
return this instanceof triggerType;
}
}
export class SpeciesFormChangeManualTrigger extends SpeciesFormChangeTrigger {}
export class SpeciesFormChangeAbilityTrigger extends SpeciesFormChangeTrigger {
public description: string = i18next.t("pokemonEvolutions:Forms.ability");
}
export class SpeciesFormChangeCompoundTrigger {
public description = "";
public triggers: SpeciesFormChangeTrigger[];
constructor(...triggers: SpeciesFormChangeTrigger[]) {
this.triggers = triggers;
this.description = this.triggers
.filter(trigger => trigger?.description?.length > 0)
.map(trigger => trigger.description)
.join(", ");
}
canChange(pokemon: Pokemon): boolean {
for (const trigger of this.triggers) {
if (!trigger.canChange(pokemon)) {
return false;
}
}
return true;
}
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
}
}
export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
public item: FormChangeItem;
public active: boolean;
constructor(item: FormChangeItem, active = true) {
super();
this.item = item;
this.active = active;
this.description = this.active
? i18next.t("pokemonEvolutions:Forms.item", {
item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`),
})
: i18next.t("pokemonEvolutions:Forms.deactivateItem", {
item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`),
});
}
canChange(pokemon: Pokemon): boolean {
return !!globalScene.findModifier(
m =>
m instanceof PokemonFormChangeItemModifier &&
m.pokemonId === pokemon.id &&
m.formChangeItem === this.item &&
m.active === this.active,
);
}
}
export class SpeciesFormChangeTimeOfDayTrigger extends SpeciesFormChangeTrigger {
public timesOfDay: TimeOfDay[];
constructor(...timesOfDay: TimeOfDay[]) {
super();
this.timesOfDay = timesOfDay;
this.description = i18next.t("pokemonEvolutions:Forms.timeOfDay");
}
canChange(_pokemon: Pokemon): boolean {
return this.timesOfDay.indexOf(globalScene.arena.getTimeOfDay()) > -1;
}
}
export class SpeciesFormChangeActiveTrigger extends SpeciesFormChangeTrigger {
public active: boolean;
constructor(active = false) {
super();
this.active = active;
this.description = this.active
? i18next.t("pokemonEvolutions:Forms.enter")
: i18next.t("pokemonEvolutions:Forms.leave");
}
canChange(pokemon: Pokemon): boolean {
return pokemon.isActive(true) === this.active;
}
}
export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigger {
public statusEffects: StatusEffect[];
public invert: boolean;
constructor(statusEffects: StatusEffect | StatusEffect[], invert = false) {
super();
if (!Array.isArray(statusEffects)) {
statusEffects = [statusEffects];
}
this.statusEffects = statusEffects;
this.invert = invert;
this.description = i18next.t("pokemonEvolutions:Forms.statusEffect");
}
canChange(pokemon: Pokemon): boolean {
return this.statusEffects.indexOf(pokemon.status?.effect || StatusEffect.NONE) > -1 !== this.invert;
}
}
export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigger {
public move: MoveId;
public known: boolean;
constructor(move: MoveId, known = true) {
super();
this.move = move;
this.known = known;
const moveKey = MoveId[this.move]
.split("_")
.filter(f => f)
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("") as unknown as string;
this.description = known
? i18next.t("pokemonEvolutions:Forms.moveLearned", {
move: i18next.t(`move:${moveKey}.name`),
})
: i18next.t("pokemonEvolutions:Forms.moveForgotten", {
move: i18next.t(`move:${moveKey}.name`),
});
}
canChange(pokemon: Pokemon): boolean {
return !!pokemon.moveset.filter(m => m.moveId === this.move).length === this.known;
}
}
export abstract class SpeciesFormChangeMoveTrigger extends SpeciesFormChangeTrigger {
public movePredicate: (m: MoveId) => boolean;
public used: boolean;
constructor(move: MoveId | ((m: MoveId) => boolean), used = true) {
super();
this.movePredicate = typeof move === "function" ? move : (m: MoveId) => m === move;
this.used = used;
}
}
export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.preMove");
canChange(pokemon: Pokemon): boolean {
const command = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
return !!command?.move && this.movePredicate(command.move.move) === this.used;
}
}
export class SpeciesFormChangePostMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.postMove");
canChange(pokemon: Pokemon): boolean {
return (
pokemon.summonData && !!pokemon.getLastXMoves(1).filter(m => this.movePredicate(m.move)).length === this.used
);
}
}
export class MeloettaFormChangePostMoveTrigger extends SpeciesFormChangePostMoveTrigger {
override canChange(pokemon: Pokemon): boolean {
if (globalScene.gameMode.hasChallenge(Challenges.SINGLE_TYPE)) {
return false;
}
// Meloetta will not transform if it has the ability Sheer Force when using Relic Song
if (pokemon.hasAbility(AbilityId.SHEER_FORCE)) {
return false;
}
return super.canChange(pokemon);
}
}
export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
private formKey: string;
constructor(formKey: string) {
super();
this.formKey = formKey;
this.description = "";
}
canChange(pokemon: Pokemon): boolean {
return (
this.formKey ===
pokemon.species.forms[globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)]
.formKey
);
}
}
/**
* Class used for triggering form changes based on the user's Tera type.
* Used by Ogerpon and Terapagos.
* @extends SpeciesFormChangeTrigger
*/
export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {
description = i18next.t("pokemonEvolutions:Forms.tera");
}
/**
* Class used for triggering form changes based on the user's lapsed Tera type.
* Used by Ogerpon and Terapagos.
* @extends SpeciesFormChangeTrigger
*/
export class SpeciesFormChangeLapseTeraTrigger extends SpeciesFormChangeTrigger {
description = i18next.t("pokemonEvolutions:Forms.teraLapse");
}
/**
* Class used for triggering form changes based on weather.
* Used by Castform and Cherrim.
* @extends SpeciesFormChangeTrigger
*/
export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
/** The ability that triggers the form change */
public ability: AbilityId;
/** The list of weathers that trigger the form change */
public weathers: WeatherType[];
constructor(ability: AbilityId, weathers: WeatherType[]) {
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weather");
}
/**
* Checks if the Pokemon has the required ability and is in the correct weather while
* the weather or ability is also not suppressed.
* @param {Pokemon} pokemon the pokemon that is trying to do the form change
* @returns `true` if the Pokemon can change forms, `false` otherwise
*/
canChange(pokemon: Pokemon): boolean {
const currentWeather = globalScene.arena.weather?.weatherType ?? WeatherType.NONE;
const isWeatherSuppressed = globalScene.arena.weather?.isEffectSuppressed();
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
return (
!isAbilitySuppressed &&
!isWeatherSuppressed &&
pokemon.hasAbility(this.ability) &&
this.weathers.includes(currentWeather)
);
}
}
/**
* Class used for reverting to the original form when the weather runs out
* or when the user loses the ability/is suppressed.
* Used by Castform and Cherrim.
* @extends SpeciesFormChangeTrigger
*/
export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChangeTrigger {
/** The ability that triggers the form change*/
public ability: AbilityId;
/** The list of weathers that will also trigger a form change to original form */
public weathers: WeatherType[];
constructor(ability: AbilityId, weathers: WeatherType[]) {
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weatherRevert");
}
/**
* Checks if the Pokemon has the required ability and the weather is one that will revert
* the Pokemon to its original form or the weather or ability is suppressed
* @param {Pokemon} pokemon the pokemon that is trying to do the form change
* @returns `true` if the Pokemon will revert to its original form, `false` otherwise
*/
canChange(pokemon: Pokemon): boolean {
if (pokemon.hasAbility(this.ability, false, true)) {
const currentWeather = globalScene.arena.weather?.weatherType ?? WeatherType.NONE;
const isWeatherSuppressed = globalScene.arena.weather?.isEffectSuppressed();
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
const summonDataAbility = pokemon.summonData.ability;
const isAbilityChanged = summonDataAbility !== this.ability && summonDataAbility !== AbilityId.NONE;
if (this.weathers.includes(currentWeather) || isWeatherSuppressed || isAbilitySuppressed || isAbilityChanged) {
return true;
}
}
return false;
}
}
export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: SpeciesFormChange, preName: string): string {
const isMega = formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1;
const isGmax = formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1;
const isEmax = formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1;
const isRevert = !isMega && formChange.formKey === pokemon.species.forms[0].formKey;
if (isMega) {
return i18next.t("battlePokemonForm:megaChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isGmax) {
return i18next.t("battlePokemonForm:gigantamaxChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isEmax) {
return i18next.t("battlePokemonForm:eternamaxChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isRevert) {
return i18next.t("battlePokemonForm:revertChange", {
pokemonName: getPokemonNameWithAffix(pokemon),
});
}
if (pokemon.getAbility().id === AbilityId.DISGUISE) {
return i18next.t("battlePokemonForm:disguiseChange");
}
return i18next.t("battlePokemonForm:formChange", { preName });
}
/** /**
* Gives a condition for form changing checking if a species is registered as caught in the player's dex data. * Gives a condition for form changing checking if a species is registered as caught in the player's dex data.
* Used for fusion forms such as Kyurem and Necrozma. * Used for fusion forms such as Kyurem and Necrozma.

View File

@ -0,0 +1,348 @@
import i18next from "i18next";
import type { Constructor } from "#app/utils/common";
import type { TimeOfDay } from "#enums/time-of-day";
import type Pokemon from "#app/field/pokemon";
import type { SpeciesFormChange } from "#app/data/pokemon-forms";
import type { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
import { getPokemonNameWithAffix } from "#app/messages";
import { globalScene } from "#app/global-scene";
import { FormChangeItem } from "#enums/form-change-item";
import { AbilityId } from "#enums/ability-id";
import { Challenges } from "#enums/challenges";
import { MoveId } from "#enums/move-id";
import { SpeciesFormKey } from "#enums/species-form-key";
import { StatusEffect } from "#enums/status-effect";
import { WeatherType } from "#enums/weather-type";
export abstract class SpeciesFormChangeTrigger {
public description = "";
canChange(_pokemon: Pokemon): boolean {
return true;
}
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
return this instanceof triggerType;
}
}
export class SpeciesFormChangeManualTrigger extends SpeciesFormChangeTrigger {}
export class SpeciesFormChangeAbilityTrigger extends SpeciesFormChangeTrigger {
public description: string = i18next.t("pokemonEvolutions:Forms.ability");
}
export class SpeciesFormChangeCompoundTrigger {
public description = "";
public triggers: SpeciesFormChangeTrigger[];
constructor(...triggers: SpeciesFormChangeTrigger[]) {
this.triggers = triggers;
this.description = this.triggers
.filter(trigger => trigger?.description?.length > 0)
.map(trigger => trigger.description)
.join(", ");
}
canChange(pokemon: Pokemon): boolean {
for (const trigger of this.triggers) {
if (!trigger.canChange(pokemon)) {
return false;
}
}
return true;
}
hasTriggerType(triggerType: Constructor<SpeciesFormChangeTrigger>): boolean {
return !!this.triggers.find(t => t.hasTriggerType(triggerType));
}
}
export class SpeciesFormChangeItemTrigger extends SpeciesFormChangeTrigger {
public item: FormChangeItem;
public active: boolean;
constructor(item: FormChangeItem, active = true) {
super();
this.item = item;
this.active = active;
this.description = this.active
? i18next.t("pokemonEvolutions:Forms.item", {
item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`),
})
: i18next.t("pokemonEvolutions:Forms.deactivateItem", {
item: i18next.t(`modifierType:FormChangeItem.${FormChangeItem[this.item]}`),
});
}
canChange(pokemon: Pokemon): boolean {
return !!globalScene.findModifier(r => {
// Assume that if m has the `formChangeItem` property, then it is a PokemonFormChangeItemModifier
const m = r as PokemonFormChangeItemModifier;
return (
"formChangeItem" in m &&
m.pokemonId === pokemon.id &&
m.formChangeItem === this.item &&
m.active === this.active
);
});
}
}
export class SpeciesFormChangeTimeOfDayTrigger extends SpeciesFormChangeTrigger {
public timesOfDay: TimeOfDay[];
constructor(...timesOfDay: TimeOfDay[]) {
super();
this.timesOfDay = timesOfDay;
this.description = i18next.t("pokemonEvolutions:Forms.timeOfDay");
}
canChange(_pokemon: Pokemon): boolean {
return this.timesOfDay.indexOf(globalScene.arena.getTimeOfDay()) > -1;
}
}
export class SpeciesFormChangeActiveTrigger extends SpeciesFormChangeTrigger {
public active: boolean;
constructor(active = false) {
super();
this.active = active;
this.description = this.active
? i18next.t("pokemonEvolutions:Forms.enter")
: i18next.t("pokemonEvolutions:Forms.leave");
}
canChange(pokemon: Pokemon): boolean {
return pokemon.isActive(true) === this.active;
}
}
export class SpeciesFormChangeStatusEffectTrigger extends SpeciesFormChangeTrigger {
public statusEffects: StatusEffect[];
public invert: boolean;
constructor(statusEffects: StatusEffect | StatusEffect[], invert = false) {
super();
if (!Array.isArray(statusEffects)) {
statusEffects = [statusEffects];
}
this.statusEffects = statusEffects;
this.invert = invert;
// this.description = i18next.t("pokemonEvolutions:Forms.statusEffect");
}
canChange(pokemon: Pokemon): boolean {
return this.statusEffects.indexOf(pokemon.status?.effect || StatusEffect.NONE) > -1 !== this.invert;
}
}
export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigger {
public move: MoveId;
public known: boolean;
constructor(move: MoveId, known = true) {
super();
this.move = move;
this.known = known;
const moveKey = MoveId[this.move]
.split("_")
.filter(f => f)
.map((f, i) => (i ? `${f[0]}${f.slice(1).toLowerCase()}` : f.toLowerCase()))
.join("") as unknown as string;
this.description = known
? i18next.t("pokemonEvolutions:Forms.moveLearned", {
move: i18next.t(`move:${moveKey}.name`),
})
: i18next.t("pokemonEvolutions:Forms.moveForgotten", {
move: i18next.t(`move:${moveKey}.name`),
});
}
canChange(pokemon: Pokemon): boolean {
return !!pokemon.moveset.filter(m => m.moveId === this.move).length === this.known;
}
}
export abstract class SpeciesFormChangeMoveTrigger extends SpeciesFormChangeTrigger {
public movePredicate: (m: MoveId) => boolean;
public used: boolean;
constructor(move: MoveId | ((m: MoveId) => boolean), used = true) {
super();
this.movePredicate = typeof move === "function" ? move : (m: MoveId) => m === move;
this.used = used;
}
}
export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.preMove");
canChange(pokemon: Pokemon): boolean {
const command = globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()];
return !!command?.move && this.movePredicate(command.move.move) === this.used;
}
}
export class SpeciesFormChangePostMoveTrigger extends SpeciesFormChangeMoveTrigger {
description = i18next.t("pokemonEvolutions:Forms.postMove");
canChange(pokemon: Pokemon): boolean {
return (
pokemon.summonData && !!pokemon.getLastXMoves(1).filter(m => this.movePredicate(m.move)).length === this.used
);
}
}
export class MeloettaFormChangePostMoveTrigger extends SpeciesFormChangePostMoveTrigger {
override canChange(pokemon: Pokemon): boolean {
if (globalScene.gameMode.hasChallenge(Challenges.SINGLE_TYPE)) {
return false;
}
// Meloetta will not transform if it has the ability Sheer Force when using Relic Song
if (pokemon.hasAbility(AbilityId.SHEER_FORCE)) {
return false;
}
return super.canChange(pokemon);
}
}
export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
private formKey: string;
constructor(formKey: string) {
super();
this.formKey = formKey;
this.description = "";
}
canChange(pokemon: Pokemon): boolean {
return (
this.formKey ===
pokemon.species.forms[globalScene.getSpeciesFormIndex(pokemon.species, pokemon.gender, pokemon.getNature(), true)]
.formKey
);
}
}
/**
* Class used for triggering form changes based on the user's Tera type.
* Used by Ogerpon and Terapagos.
*/
export class SpeciesFormChangeTeraTrigger extends SpeciesFormChangeTrigger {}
/**
* Class used for triggering form changes based on the user's lapsed Tera type.
* Used by Ogerpon and Terapagos.
*/
export class SpeciesFormChangeLapseTeraTrigger extends SpeciesFormChangeTrigger {}
/**
* Class used for triggering form changes based on weather.
* Used by Castform and Cherrim.
*/
export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
/** The ability that triggers the form change */
public ability: AbilityId;
/** The list of weathers that trigger the form change */
public weathers: WeatherType[];
constructor(ability: AbilityId, weathers: WeatherType[]) {
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weather");
}
/**
* Checks if the Pokemon has the required ability and is in the correct weather while
* the weather or ability is also not suppressed.
* @param pokemon - The pokemon that is trying to do the form change
* @returns `true` if the Pokemon can change forms, `false` otherwise
*/
canChange(pokemon: Pokemon): boolean {
const currentWeather = globalScene.arena.weather?.weatherType ?? WeatherType.NONE;
const isWeatherSuppressed = globalScene.arena.weather?.isEffectSuppressed();
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
return (
!isAbilitySuppressed &&
!isWeatherSuppressed &&
pokemon.hasAbility(this.ability) &&
this.weathers.includes(currentWeather)
);
}
}
/**
* Class used for reverting to the original form when the weather runs out
* or when the user loses the ability/is suppressed.
* Used by Castform and Cherrim.
*/
export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChangeTrigger {
/** The ability that triggers the form change*/
public ability: AbilityId;
/** The list of weathers that will also trigger a form change to original form */
public weathers: WeatherType[];
constructor(ability: AbilityId, weathers: WeatherType[]) {
super();
this.ability = ability;
this.weathers = weathers;
this.description = i18next.t("pokemonEvolutions:Forms.weatherRevert");
}
/**
* Checks if the Pokemon has the required ability and the weather is one that will revert
* the Pokemon to its original form or the weather or ability is suppressed
* @param {Pokemon} pokemon the pokemon that is trying to do the form change
* @returns `true` if the Pokemon will revert to its original form, `false` otherwise
*/
canChange(pokemon: Pokemon): boolean {
if (pokemon.hasAbility(this.ability, false, true)) {
const currentWeather = globalScene.arena.weather?.weatherType ?? WeatherType.NONE;
const isWeatherSuppressed = globalScene.arena.weather?.isEffectSuppressed();
const isAbilitySuppressed = pokemon.summonData.abilitySuppressed;
const summonDataAbility = pokemon.summonData.ability;
const isAbilityChanged = summonDataAbility !== this.ability && summonDataAbility !== AbilityId.NONE;
if (this.weathers.includes(currentWeather) || isWeatherSuppressed || isAbilitySuppressed || isAbilityChanged) {
return true;
}
}
return false;
}
}
export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: SpeciesFormChange, preName: string): string {
const isMega = formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1;
const isGmax = formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1;
const isEmax = formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1;
const isRevert = !isMega && formChange.formKey === pokemon.species.forms[0].formKey;
if (isMega) {
return i18next.t("battlePokemonForm:megaChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isGmax) {
return i18next.t("battlePokemonForm:gigantamaxChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isEmax) {
return i18next.t("battlePokemonForm:eternamaxChange", {
preName,
pokemonName: pokemon.name,
});
}
if (isRevert) {
return i18next.t("battlePokemonForm:revertChange", {
pokemonName: getPokemonNameWithAffix(pokemon),
});
}
if (pokemon.getAbility().id === AbilityId.DISGUISE) {
return i18next.t("battlePokemonForm:disguiseChange");
}
return i18next.t("battlePokemonForm:formChange", { preName });
}

View File

@ -38,7 +38,10 @@ import { SpeciesId } from "#enums/species-id";
import { TimeOfDay } from "#enums/time-of-day"; import { TimeOfDay } from "#enums/time-of-day";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms"; import {
SpeciesFormChangeRevertWeatherFormTrigger,
SpeciesFormChangeWeatherTrigger,
} from "#app/data/pokemon-forms/form-change-triggers";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { FieldEffectModifier } from "#app/modifier/modifier"; import { FieldEffectModifier } from "#app/modifier/modifier";

View File

@ -214,7 +214,7 @@ import {
SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeLapseTeraTrigger,
SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveLearnedTrigger,
SpeciesFormChangePostMoveTrigger, SpeciesFormChangePostMoveTrigger,
} from "#app/data/pokemon-forms"; } from "#app/data/pokemon-forms/form-change-triggers";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain";
import type { TrainerSlot } from "#enums/trainer-slot"; import type { TrainerSlot } from "#enums/trainer-slot";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";

View File

@ -6,7 +6,8 @@ import { AttackMove } from "#app/data/moves/move";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { getNatureName, getNatureStatMultiplier } from "#app/data/nature"; import { getNatureName, getNatureStatMultiplier } from "#app/data/nature";
import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { getPokeballCatchMultiplier, getPokeballName, MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
import { pokemonFormChanges, SpeciesFormChangeCondition, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; import { pokemonFormChanges, SpeciesFormChangeCondition } from "#app/data/pokemon-forms";
import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { FormChangeItem } from "#enums/form-change-item"; import { FormChangeItem } from "#enums/form-change-item";
import { getStatusEffectDescriptor } from "#app/data/status-effect"; import { getStatusEffectDescriptor } from "#app/data/status-effect";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";

View File

@ -3,7 +3,7 @@ import { getBerryEffectFunc, getBerryPredicate } from "#app/data/berry";
import { getLevelTotalExp } from "#app/data/exp"; import { getLevelTotalExp } from "#app/data/exp";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball"; import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import type { FormChangeItem } from "#enums/form-change-item"; import type { FormChangeItem } from "#enums/form-change-item";
import { getStatusEffectHealText } from "#app/data/status-effect"; import { getStatusEffectHealText } from "#app/data/status-effect";
import Pokemon, { type PlayerPokemon } from "#app/field/pokemon"; import Pokemon, { type PlayerPokemon } from "#app/field/pokemon";

View File

@ -13,7 +13,7 @@ import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type";
import { battleSpecDialogue } from "#app/data/dialogue"; import { battleSpecDialogue } from "#app/data/dialogue";
import { PostVictoryStatStageChangeAttr } from "#app/data/moves/move"; import { PostVictoryStatStageChangeAttr } from "#app/data/moves/move";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { BattleSpec } from "#app/enums/battle-spec"; import { BattleSpec } from "#app/enums/battle-spec";
import { StatusEffect } from "#app/enums/status-effect"; import { StatusEffect } from "#app/enums/status-effect";
import type { EnemyPokemon } from "#app/field/pokemon"; import type { EnemyPokemon } from "#app/field/pokemon";

View File

@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { fixedInt } from "#app/utils/common"; import { fixedInt } from "#app/utils/common";
import { achvs } from "../system/achv"; import { achvs } from "../system/achv";
import type { SpeciesFormChange } from "../data/pokemon-forms"; import type { SpeciesFormChange } from "../data/pokemon-forms";
import { getSpeciesFormChangeMessage } from "../data/pokemon-forms"; import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms/form-change-triggers";
import type { PlayerPokemon } from "../field/pokemon"; import type { PlayerPokemon } from "../field/pokemon";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import type PartyUiHandler from "../ui/party-ui-handler"; import type PartyUiHandler from "../ui/party-ui-handler";

View File

@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims"; import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";

View File

@ -49,7 +49,7 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { MoveTarget } from "#enums/MoveTarget"; import { MoveTarget } from "#enums/MoveTarget";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import type { DamageResult, TurnMove } from "#app/field/pokemon"; import type { DamageResult, TurnMove } from "#app/field/pokemon";
import { PokemonMove } from "#app/data/moves/pokemon-move"; import { PokemonMove } from "#app/data/moves/pokemon-move";

View File

@ -29,7 +29,7 @@ import {
} from "#app/data/moves/move"; } from "#app/data/moves/move";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect"; import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { getTerrainBlockMessage, getWeatherBlockMessage } from "#app/data/weather"; import { getTerrainBlockMessage, getWeatherBlockMessage } from "#app/data/weather";

View File

@ -7,7 +7,7 @@ import { StatusEffect } from "#app/enums/status-effect";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeStatusEffectTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilities/ability"; import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilities/ability";
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";

View File

@ -1,7 +1,10 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { SemiInvulnerableTag } from "#app/data/battler-tags"; import { SemiInvulnerableTag } from "#app/data/battler-tags";
import type { SpeciesFormChange } from "#app/data/pokemon-forms"; import type { SpeciesFormChange } from "#app/data/pokemon-forms";
import { getSpeciesFormChangeMessage, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; import {
getSpeciesFormChangeMessage,
SpeciesFormChangeTeraTrigger,
} from "#app/data/pokemon-forms/form-change-triggers";
import { getTypeRgb } from "#app/data/type"; import { getTypeRgb } from "#app/data/type";
import { BattleSpec } from "#app/enums/battle-spec"; import { BattleSpec } from "#app/enums/battle-spec";
import { BattlerTagType } from "#app/enums/battler-tag-type"; import { BattlerTagType } from "#app/enums/battler-tag-type";

View File

@ -1,5 +1,5 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
import { SwitchSummonPhase } from "./switch-summon-phase"; import { SwitchSummonPhase } from "./switch-summon-phase";

View File

@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { applyChallenges } from "#app/data/challenge"; import { applyChallenges } from "#app/data/challenge";
import { ChallengeType } from "#enums/challenge-type"; import { ChallengeType } from "#enums/challenge-type";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { overrideHeldItems, overrideModifiers } from "#app/modifier/modifier"; import { overrideHeldItems, overrideModifiers } from "#app/modifier/modifier";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";

View File

@ -1,6 +1,6 @@
import { BattleType } from "#enums/battle-type"; import { BattleType } from "#enums/battle-type";
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import { PlayerGender } from "#app/enums/player-gender"; import { PlayerGender } from "#app/enums/player-gender";
import { addPokeballOpenParticles } from "#app/field/anims"; import { addPokeballOpenParticles } from "#app/field/anims";

View File

@ -9,7 +9,7 @@ import {
import { ForceSwitchOutAttr } from "#app/data/moves/move"; import { ForceSwitchOutAttr } from "#app/data/moves/move";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballTintColor } from "#app/data/pokeball";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";

View File

@ -5,7 +5,7 @@ import i18next from "i18next";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import { SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { CommonBattleAnim } from "#app/data/battle-anims"; import { CommonBattleAnim } from "#app/data/battle-anims";
import { CommonAnim } from "#enums/move-anims-common"; import { CommonAnim } from "#enums/move-anims-common";

View File

@ -19,7 +19,7 @@ import { StatusEffect } from "#enums/status-effect";
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "#app/ui/pokemon-icon-anim-handler";
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import { addWindow } from "#app/ui/ui-theme"; import { addWindow } from "#app/ui/ui-theme";
import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms/form-change-triggers";
import { FormChangeItem } from "#enums/form-change-item"; import { FormChangeItem } from "#enums/form-change-item";
import { getVariantTint } from "#app/sprites/variant"; import { getVariantTint } from "#app/sprites/variant";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";