Merge branch 'beta' into test-doc

This commit is contained in:
NightKev 2025-06-07 17:56:39 -07:00 committed by GitHub
commit c7746bc1ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
144 changed files with 1106 additions and 841 deletions

View File

@ -42,9 +42,6 @@
// TODO: Remove if we ever get down to 0 circular imports // TODO: Remove if we ever get down to 0 circular imports
"organizeImports": { "enabled": false }, "organizeImports": { "enabled": false },
"linter": { "linter": {
"ignore": [
"src/phases/move-effect-phase.ts" // TODO: unignore after move-effect-phase refactor
],
"enabled": true, "enabled": true,
"rules": { "rules": {
"recommended": true, "recommended": true,

View File

@ -145,6 +145,5 @@
</div> </div>
<script type="module" src="./src/main.ts"></script> <script type="module" src="./src/main.ts"></script>
<script src="./src/touch-controls.ts" type="module"></script> <script src="./src/touch-controls.ts" type="module"></script>
<script src="./src/debug.js" type="module"></script>
</body> </body>
</html> </html>

View File

@ -9,6 +9,11 @@ pre-commit:
- rebase - rebase
post-merge: post-merge:
commands:
update-submodules:
run: git submodule update --init --recursive
post-checkout:
commands: commands:
update-submodules: update-submodules:
run: git submodule update --init --recursive run: git submodule update --init --recursive

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,6 +1,7 @@
/** export interface DexData {
* Dex entry for a single Pokemon Species [key: number]: DexEntry;
*/ }
export interface DexEntry { export interface DexEntry {
seenAttr: bigint; seenAttr: bigint;
caughtAttr: bigint; caughtAttr: bigint;
@ -10,7 +11,3 @@ export interface DexEntry {
hatchedCount: number; hatchedCount: number;
ivs: number[]; ivs: number[];
} }
export interface DexData {
[key: number]: DexEntry;
}

View File

@ -2,9 +2,6 @@ export interface Localizable {
localize(): void; localize(): void;
} }
export interface TranslationEntries {
[key: string]: string | { [key: string]: string };
}
export interface SimpleTranslationEntries { export interface SimpleTranslationEntries {
[key: string]: string; [key: string]: string;
} }

286
src/@types/phase-types.ts Normal file
View File

@ -0,0 +1,286 @@
import type { MoveAnim } from "#app/data/battle-anims";
import type { AddEnemyBuffModifierPhase } from "#app/phases/add-enemy-buff-modifier-phase";
import type { AttemptCapturePhase } from "#app/phases/attempt-capture-phase";
import type { AttemptRunPhase } from "#app/phases/attempt-run-phase";
import type { BattleEndPhase } from "#app/phases/battle-end-phase";
import type { BerryPhase } from "#app/phases/berry-phase";
import type { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import type { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import type { CommandPhase } from "#app/phases/command-phase";
import type { CommonAnimPhase } from "#app/phases/common-anim-phase";
import type { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import type { EggHatchPhase } from "#app/phases/egg-hatch-phase";
import type { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import type { EggSummaryPhase } from "#app/phases/egg-summary-phase";
import type { EncounterPhase } from "#app/phases/encounter-phase";
import type { EndCardPhase } from "#app/phases/end-card-phase";
import type { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import type { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import type { EvolutionPhase } from "#app/phases/evolution-phase";
import type { ExpPhase } from "#app/phases/exp-phase";
import type { FaintPhase } from "#app/phases/faint-phase";
import type { FormChangePhase } from "#app/phases/form-change-phase";
import type { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
import type { GameOverPhase } from "#app/phases/game-over-phase";
import type { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import type { HidePartyExpBarPhase } from "#app/phases/hide-party-exp-bar-phase";
import type { LearnMovePhase } from "#app/phases/learn-move-phase";
import type { LevelCapPhase } from "#app/phases/level-cap-phase";
import type { LevelUpPhase } from "#app/phases/level-up-phase";
import type { LoadMoveAnimPhase } from "#app/phases/load-move-anim-phase";
import type { LoginPhase } from "#app/phases/login-phase";
import type { MessagePhase } from "#app/phases/message-phase";
import type { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import type { MoneyRewardPhase } from "#app/phases/money-reward-phase";
import type { MoveAnimPhase } from "#app/phases/move-anim-phase";
import type { MoveChargePhase } from "#app/phases/move-charge-phase";
import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
import type { MoveEndPhase } from "#app/phases/move-end-phase";
import type { MoveHeaderPhase } from "#app/phases/move-header-phase";
import type { MovePhase } from "#app/phases/move-phase";
import type {
MysteryEncounterPhase,
MysteryEncounterOptionSelectedPhase,
MysteryEncounterBattlePhase,
MysteryEncounterRewardsPhase,
PostMysteryEncounterPhase,
MysteryEncounterBattleStartCleanupPhase,
} from "#app/phases/mystery-encounter-phases";
import type { NewBattlePhase } from "#app/phases/new-battle-phase";
import type { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import type { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import type { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import type { PartyExpPhase } from "#app/phases/party-exp-phase";
import type { PartyHealPhase } from "#app/phases/party-heal-phase";
import type { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import type { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import type { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase";
import type { PostGameOverPhase } from "#app/phases/post-game-over-phase";
import type { PostSummonPhase } from "#app/phases/post-summon-phase";
import type { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import type { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import type { ReloadSessionPhase } from "#app/phases/reload-session-phase";
import type { ResetStatusPhase } from "#app/phases/reset-status-phase";
import type { ReturnPhase } from "#app/phases/return-phase";
import type { RevivalBlessingPhase } from "#app/phases/revival-blessing-phase";
import type { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
import type { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import type { SelectBiomePhase } from "#app/phases/select-biome-phase";
import type { SelectChallengePhase } from "#app/phases/select-challenge-phase";
import type { SelectGenderPhase } from "#app/phases/select-gender-phase";
import type { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import type { SelectStarterPhase } from "#app/phases/select-starter-phase";
import type { SelectTargetPhase } from "#app/phases/select-target-phase";
import type { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
import type { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import type { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import type { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import type { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import type { SummonMissingPhase } from "#app/phases/summon-missing-phase";
import type { SummonPhase } from "#app/phases/summon-phase";
import type { SwitchBiomePhase } from "#app/phases/switch-biome-phase";
import type { SwitchPhase } from "#app/phases/switch-phase";
import type { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import type { TeraPhase } from "#app/phases/tera-phase";
import type { TitlePhase } from "#app/phases/title-phase";
import type { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import type { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
import type { TurnEndPhase } from "#app/phases/turn-end-phase";
import type { TurnInitPhase } from "#app/phases/turn-init-phase";
import type { TurnStartPhase } from "#app/phases/turn-start-phase";
import type { UnavailablePhase } from "#app/phases/unavailable-phase";
import type { UnlockPhase } from "#app/phases/unlock-phase";
import type { VictoryPhase } from "#app/phases/victory-phase";
import type { WeatherEffectPhase } from "#app/phases/weather-effect-phase";
export type PhaseClass =
| typeof AddEnemyBuffModifierPhase
| typeof AttemptCapturePhase
| typeof AttemptRunPhase
| typeof BattleEndPhase
| typeof BerryPhase
| typeof CheckStatusEffectPhase
| typeof CheckSwitchPhase
| typeof CommandPhase
| typeof CommonAnimPhase
| typeof DamageAnimPhase
| typeof EggHatchPhase
| typeof EggLapsePhase
| typeof EggSummaryPhase
| typeof EncounterPhase
| typeof EndCardPhase
| typeof EndEvolutionPhase
| typeof EnemyCommandPhase
| typeof EvolutionPhase
| typeof FormChangePhase
| typeof ExpPhase
| typeof FaintPhase
| typeof FormChangePhase
| typeof GameOverPhase
| typeof GameOverModifierRewardPhase
| typeof HideAbilityPhase
| typeof HidePartyExpBarPhase
| typeof LearnMovePhase
| typeof LevelUpPhase
| typeof LevelCapPhase
| typeof LoadMoveAnimPhase
| typeof LoginPhase
| typeof MessagePhase
| typeof ModifierRewardPhase
| typeof MoneyRewardPhase
| typeof MoveAnimPhase
| typeof MoveChargePhase
| typeof MoveEffectPhase
| typeof MoveEndPhase
| typeof MoveHeaderPhase
| typeof MovePhase
| typeof MysteryEncounterPhase
| typeof MysteryEncounterOptionSelectedPhase
| typeof MysteryEncounterBattlePhase
| typeof MysteryEncounterRewardsPhase
| typeof MysteryEncounterBattleStartCleanupPhase
| typeof MysteryEncounterRewardsPhase
| typeof PostMysteryEncounterPhase
| typeof NewBattlePhase
| typeof NewBiomeEncounterPhase
| typeof NextEncounterPhase
| typeof ObtainStatusEffectPhase
| typeof PartyExpPhase
| typeof PartyHealPhase
| typeof PokemonAnimPhase
| typeof PokemonHealPhase
| typeof PokemonTransformPhase
| typeof PostGameOverPhase
| typeof PostSummonPhase
| typeof PostTurnStatusEffectPhase
| typeof QuietFormChangePhase
| typeof ReloadSessionPhase
| typeof ResetStatusPhase
| typeof ReturnPhase
| typeof RevivalBlessingPhase
| typeof RibbonModifierRewardPhase
| typeof ScanIvsPhase
| typeof SelectBiomePhase
| typeof SelectChallengePhase
| typeof SelectGenderPhase
| typeof SelectModifierPhase
| typeof SelectStarterPhase
| typeof SelectTargetPhase
| typeof ShinySparklePhase
| typeof ShowAbilityPhase
| typeof ShowTrainerPhase
| typeof ShowPartyExpBarPhase
| typeof StatStageChangePhase
| typeof SummonMissingPhase
| typeof SummonPhase
| typeof SwitchBiomePhase
| typeof SwitchPhase
| typeof SwitchSummonPhase
| typeof TeraPhase
| typeof TitlePhase
| typeof ToggleDoublePositionPhase
| typeof TrainerVictoryPhase
| typeof TurnEndPhase
| typeof TurnInitPhase
| typeof TurnStartPhase
| typeof UnavailablePhase
| typeof UnlockPhase
| typeof VictoryPhase
| typeof WeatherEffectPhase;
/** Typescript map used to map a string phase to the actual phase type */
export type PhaseMap = {
AddEnemyBuffModifierPhase: AddEnemyBuffModifierPhase;
AttemptCapturePhase: AttemptCapturePhase;
AttemptRunPhase: AttemptRunPhase;
BattleEndPhase: BattleEndPhase;
BerryPhase: BerryPhase;
CheckStatusEffectPhase: CheckStatusEffectPhase;
CheckSwitchPhase: CheckSwitchPhase;
CommandPhase: CommandPhase;
CommonAnimPhase: CommonAnimPhase;
DamageAnimPhase: DamageAnimPhase;
EggHatchPhase: EggHatchPhase;
EggLapsePhase: EggLapsePhase;
EggSummaryPhase: EggSummaryPhase;
EncounterPhase: EncounterPhase;
EndCardPhase: EndCardPhase;
EndEvolutionPhase: EndEvolutionPhase;
EnemyCommandPhase: EnemyCommandPhase;
EvolutionPhase: EvolutionPhase;
ExpPhase: ExpPhase;
FaintPhase: FaintPhase;
FormChangePhase: FormChangePhase;
GameOverPhase: GameOverPhase;
GameOverModifierRewardPhase: GameOverModifierRewardPhase;
HideAbilityPhase: HideAbilityPhase;
HidePartyExpBarPhase: HidePartyExpBarPhase;
LearnMovePhase: LearnMovePhase;
LevelCapPhase: LevelCapPhase;
LevelUpPhase: LevelUpPhase;
LoadMoveAnimPhase: LoadMoveAnimPhase;
LoginPhase: LoginPhase;
MessagePhase: MessagePhase;
ModifierRewardPhase: ModifierRewardPhase;
MoneyRewardPhase: MoneyRewardPhase;
MoveAnimPhase: MoveAnimPhase<MoveAnim>;
MoveChargePhase: MoveChargePhase;
MoveEffectPhase: MoveEffectPhase;
MoveEndPhase: MoveEndPhase;
MoveHeaderPhase: MoveHeaderPhase;
MovePhase: MovePhase;
MysteryEncounterPhase: MysteryEncounterPhase;
MysteryEncounterOptionSelectedPhase: MysteryEncounterOptionSelectedPhase;
MysteryEncounterBattlePhase: MysteryEncounterBattlePhase;
MysteryEncounterBattleStartCleanupPhase: MysteryEncounterBattleStartCleanupPhase;
MysteryEncounterRewardsPhase: MysteryEncounterRewardsPhase;
PostMysteryEncounterPhase: PostMysteryEncounterPhase;
NewBattlePhase: NewBattlePhase;
NewBiomeEncounterPhase: NewBiomeEncounterPhase;
NextEncounterPhase: NextEncounterPhase;
ObtainStatusEffectPhase: ObtainStatusEffectPhase;
PartyExpPhase: PartyExpPhase;
PartyHealPhase: PartyHealPhase;
PokemonAnimPhase: PokemonAnimPhase;
PokemonHealPhase: PokemonHealPhase;
PokemonTransformPhase: PokemonTransformPhase;
PostGameOverPhase: PostGameOverPhase;
PostSummonPhase: PostSummonPhase;
PostTurnStatusEffectPhase: PostTurnStatusEffectPhase;
QuietFormChangePhase: QuietFormChangePhase;
ReloadSessionPhase: ReloadSessionPhase;
ResetStatusPhase: ResetStatusPhase;
ReturnPhase: ReturnPhase;
RevivalBlessingPhase: RevivalBlessingPhase;
RibbonModifierRewardPhase: RibbonModifierRewardPhase;
ScanIvsPhase: ScanIvsPhase;
SelectBiomePhase: SelectBiomePhase;
SelectChallengePhase: SelectChallengePhase;
SelectGenderPhase: SelectGenderPhase;
SelectModifierPhase: SelectModifierPhase;
SelectStarterPhase: SelectStarterPhase;
SelectTargetPhase: SelectTargetPhase;
ShinySparklePhase: ShinySparklePhase;
ShowAbilityPhase: ShowAbilityPhase;
ShowPartyExpBarPhase: ShowPartyExpBarPhase;
ShowTrainerPhase: ShowTrainerPhase;
StatStageChangePhase: StatStageChangePhase;
SummonMissingPhase: SummonMissingPhase;
SummonPhase: SummonPhase;
SwitchBiomePhase: SwitchBiomePhase;
SwitchPhase: SwitchPhase;
SwitchSummonPhase: SwitchSummonPhase;
TeraPhase: TeraPhase;
TitlePhase: TitlePhase;
ToggleDoublePositionPhase: ToggleDoublePositionPhase;
TrainerVictoryPhase: TrainerVictoryPhase;
TurnEndPhase: TurnEndPhase;
TurnInitPhase: TurnInitPhase;
TurnStartPhase: TurnStartPhase;
UnavailablePhase: UnavailablePhase;
UnlockPhase: UnlockPhase;
VictoryPhase: VictoryPhase;
WeatherEffectPhase: WeatherEffectPhase;
};
export type PhaseString = keyof PhaseMap;

View File

@ -2,8 +2,8 @@ import type { EnemyPokemon } from "#app/field/pokemon";
import type { PersistentModifier } from "#app/modifier/modifier"; import type { PersistentModifier } from "#app/modifier/modifier";
import type { PartyMemberStrength } from "#enums/party-member-strength"; import type { PartyMemberStrength } from "#enums/party-member-strength";
import type { SpeciesId } from "#enums/species-id"; import type { SpeciesId } from "#enums/species-id";
import type { TrainerConfig } from "./trainer-config"; import type { TrainerConfig } from "../data/trainers/trainer-config";
import type { TrainerPartyTemplate } from "./TrainerPartyTemplate"; import type { TrainerPartyTemplate } from "../data/trainers/TrainerPartyTemplate";
export type PartyTemplateFunc = () => TrainerPartyTemplate; export type PartyTemplateFunc = () => TrainerPartyTemplate;
export type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon; export type PartyMemberFunc = (level: number, strength: PartyMemberStrength) => EnemyPokemon;

View File

@ -120,7 +120,7 @@ import { SceneBase } from "#app/scene-base";
import CandyBar from "#app/ui/candy-bar"; import CandyBar from "#app/ui/candy-bar";
import type { Variant } from "#app/sprites/variant"; import type { Variant } from "#app/sprites/variant";
import { variantData, clearVariantData } from "#app/sprites/variant"; import { variantData, clearVariantData } from "#app/sprites/variant";
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/@types/locales";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { InputsController } from "#app/inputs-controller"; import { InputsController } from "#app/inputs-controller";
import { UiInputs } from "#app/ui-inputs"; import { UiInputs } from "#app/ui-inputs";
@ -145,7 +145,7 @@ import { LoadingScene } from "#app/loading-scene";
import { LevelCapPhase } from "#app/phases/level-cap-phase"; import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LoginPhase } from "#app/phases/login-phase"; import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "#app/phases/message-phase"; import { MessagePhase } from "#app/phases/message-phase";
import { MovePhase } from "#app/phases/move-phase"; import type { MovePhase } from "#app/phases/move-phase";
import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase"; import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "#app/phases/next-encounter-phase"; import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase"; import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
@ -153,7 +153,6 @@ import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { ReturnPhase } from "#app/phases/return-phase"; import { ReturnPhase } from "#app/phases/return-phase";
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase"; import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { SummonPhase } from "#app/phases/summon-phase"; import { SummonPhase } from "#app/phases/summon-phase";
import { SwitchPhase } from "#app/phases/switch-phase";
import { TitlePhase } from "#app/phases/title-phase"; import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase"; import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { TurnInitPhase } from "#app/phases/turn-init-phase";
@ -170,7 +169,7 @@ import {
import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data"; import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import { ExpPhase } from "#app/phases/exp-phase"; import { ExpPhase } from "#app/phases/exp-phase";
import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase"; import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
@ -812,6 +811,7 @@ export default class BattleScene extends SceneBase {
} }
} }
// TODO: Add a `getPartyOnSide` function for getting the party of a pokemon
public getPlayerParty(): PlayerPokemon[] { public getPlayerParty(): PlayerPokemon[] {
return this.party; return this.party;
} }
@ -901,7 +901,7 @@ export default class BattleScene extends SceneBase {
do { do {
targetingMovePhase = this.findPhase( targetingMovePhase = this.findPhase(
mp => mp =>
mp instanceof MovePhase && mp.is("MovePhase") &&
mp.targets.length === 1 && mp.targets.length === 1 &&
mp.targets[0] === removedPokemon.getBattlerIndex() && mp.targets[0] === removedPokemon.getBattlerIndex() &&
mp.pokemon.isPlayer() !== allyPokemon.isPlayer(), mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),
@ -1450,7 +1450,7 @@ export default class BattleScene extends SceneBase {
} }
if (lastBattle?.double && !newDouble) { if (lastBattle?.double && !newDouble) {
this.tryRemovePhase(p => p instanceof SwitchPhase); this.tryRemovePhase((p: Phase) => p.is("SwitchPhase"));
for (const p of this.getPlayerField()) { for (const p of this.getPlayerField()) {
p.lapseTag(BattlerTagType.COMMANDED); p.lapseTag(BattlerTagType.COMMANDED);
} }
@ -1588,9 +1588,7 @@ export default class BattleScene extends SceneBase {
return 0; return 0;
} }
const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes( const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes(this.getCurrentPhase()?.phaseName ?? "");
this.getCurrentPhase()?.constructor.name ?? "",
);
if ( if (
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros. // Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
@ -3089,9 +3087,9 @@ export default class BattleScene extends SceneBase {
const removeOld = itemModifier.stackCount === 0; const removeOld = itemModifier.stackCount === 0;
if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { if (!removeOld || !source || this.removeModifier(itemModifier, source.isEnemy())) {
const addModifier = () => { const addModifier = () => {
if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { if (!matchingModifier || this.removeModifier(matchingModifier, target.isEnemy())) {
if (target.isPlayer()) { if (target.isPlayer()) {
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant); this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant);
if (source && itemLost) { if (source && itemLost) {
@ -3495,12 +3493,12 @@ export default class BattleScene extends SceneBase {
} }
if (matchingFormChange) { if (matchingFormChange) {
let phase: Phase; let phase: Phase;
if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet) { if (pokemon.isPlayer() && !matchingFormChange.quiet) {
phase = new FormChangePhase(pokemon, matchingFormChange, modal); phase = new FormChangePhase(pokemon, matchingFormChange, modal);
} else { } else {
phase = new QuietFormChangePhase(pokemon, matchingFormChange); phase = new QuietFormChangePhase(pokemon, matchingFormChange);
} }
if (pokemon instanceof PlayerPokemon && !matchingFormChange.quiet && modal) { if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) {
this.overridePhase(phase); this.overridePhase(phase);
} else if (delayed) { } else if (delayed) {
this.pushPhase(phase); this.pushPhase(phase);
@ -3569,21 +3567,18 @@ export default class BattleScene extends SceneBase {
gameMode: this.currentBattle ? this.gameMode.getName() : "Title", gameMode: this.currentBattle ? this.gameMode.getName() : "Title",
biome: this.currentBattle ? getBiomeName(this.arena.biomeType) : "", biome: this.currentBattle ? getBiomeName(this.arena.biomeType) : "",
wave: this.currentBattle?.waveIndex ?? 0, wave: this.currentBattle?.waveIndex ?? 0,
party: this.party party:
? this.party.map(p => { this.party?.map(p => ({
return { name: p.name,
name: p.name, form: p.getFormKey(),
form: p.getFormKey(), types: p.getTypes().map(type => PokemonType[type]),
types: p.getTypes().map(type => PokemonType[type]), teraType: PokemonType[p.getTeraType()],
teraType: PokemonType[p.getTeraType()], isTerastallized: p.isTerastallized,
isTerastallized: p.isTerastallized, level: p.level,
level: p.level, currentHP: p.hp,
currentHP: p.hp, maxHP: p.getMaxHp(),
maxHP: p.getMaxHp(), status: p.status?.effect ? StatusEffect[p.status.effect] : "",
status: p.status?.effect ? StatusEffect[p.status.effect] : "", })) ?? [], // TODO: review if this can be nullish
};
})
: [],
modeChain: this.ui?.getModeChain() ?? [], modeChain: this.ui?.getModeChain() ?? [],
}; };
(window as any).gameInfo = gameInfo; (window as any).gameInfo = gameInfo;
@ -3601,7 +3596,7 @@ export default class BattleScene extends SceneBase {
activePokemon = activePokemon.concat(this.getEnemyParty()); activePokemon = activePokemon.concat(this.getEnemyParty());
for (const p of activePokemon) { for (const p of activePokemon) {
keys.push(p.getSpriteKey(true)); keys.push(p.getSpriteKey(true));
if (p instanceof PlayerPokemon) { if (p.isPlayer()) {
keys.push(p.getBattleSpriteKey(true, true)); keys.push(p.getBattleSpriteKey(true, true));
} }
keys.push(p.species.getCryKey(p.formIndex)); keys.push(p.species.getCryKey(p.formIndex));
@ -3617,7 +3612,7 @@ export default class BattleScene extends SceneBase {
* @param pokemon The (enemy) pokemon * @param pokemon The (enemy) pokemon
*/ */
initFinalBossPhaseTwo(pokemon: Pokemon): void { initFinalBossPhaseTwo(pokemon: Pokemon): void {
if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { if (pokemon.isEnemy() && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) {
this.fadeOutBgm(fixedInt(2000), false); this.fadeOutBgm(fixedInt(2000), false);
this.ui.showDialogue( this.ui.showDialogue(
battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin,
@ -3966,16 +3961,13 @@ export default class BattleScene extends SceneBase {
if (previousEncounter !== null && encounterType === previousEncounter) { if (previousEncounter !== null && encounterType === previousEncounter) {
return false; return false;
} }
if ( return !(
this.mysteryEncounterSaveData.encounteredEvents.length > 0 && this.mysteryEncounterSaveData.encounteredEvents.length > 0 &&
encounterCandidate.maxAllowedEncounters && encounterCandidate.maxAllowedEncounters &&
encounterCandidate.maxAllowedEncounters > 0 && encounterCandidate.maxAllowedEncounters > 0 &&
this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length >= this.mysteryEncounterSaveData.encounteredEvents.filter(e => e.type === encounterType).length >=
encounterCandidate.maxAllowedEncounters encounterCandidate.maxAllowedEncounters
) { );
return false;
}
return true;
}) })
.map(m => allMysteryEncounters[m]); .map(m => allMysteryEncounters[m]);
// Decrement tier // Decrement tier

View File

@ -197,10 +197,7 @@ export function canIAssignThisKey(config, key) {
export function canIOverrideThisSetting(config, settingName) { export function canIOverrideThisSetting(config, settingName) {
const key = getKeyWithSettingName(config, settingName); const key = getKeyWithSettingName(config, settingName);
// || isTheLatestBind(config, settingName) no longer needed since action and cancel are protected // || isTheLatestBind(config, settingName) no longer needed since action and cancel are protected
if (config.blacklist?.includes(key)) { return !config.blacklist?.includes(key);
return false;
}
return true;
} }
export function canIDeleteThisKey(config, key) { export function canIDeleteThisKey(config, key) {

View File

@ -2,7 +2,7 @@ import { AbilityId } from "#enums/ability-id";
import type { AbAttrCondition } from "#app/@types/ability-types"; import type { AbAttrCondition } from "#app/@types/ability-types";
import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
import i18next from "i18next"; import i18next from "i18next";
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/@types/locales";
import type { Constructor } from "#app/utils/common"; import type { Constructor } from "#app/utils/common";
export class Ability implements Localizable { export class Ability implements Localizable {

View File

@ -1246,7 +1246,7 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr {
/** /**
* Determine if the move type change attribute can be applied * Determine if the move type change attribute can be applied
* *
* Can be applied if: * Can be applied if:
* - The ability's condition is met, e.g. pixilate only boosts normal moves, * - The ability's condition is met, e.g. pixilate only boosts normal moves,
* - The move is not forbidden from having its type changed by an ability, e.g. {@linkcode MoveId.MULTI_ATTACK} * - The move is not forbidden from having its type changed by an ability, e.g. {@linkcode MoveId.MULTI_ATTACK}
@ -1262,7 +1262,7 @@ export class MoveTypeChangeAbAttr extends PreAttackAbAttr {
*/ */
override canApplyPreAttack(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _defender: Pokemon | null, move: Move, _args: [NumberHolder?, NumberHolder?, ...any]): boolean { override canApplyPreAttack(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _defender: Pokemon | null, move: Move, _args: [NumberHolder?, NumberHolder?, ...any]): boolean {
return (!this.condition || this.condition(pokemon, _defender, move)) && return (!this.condition || this.condition(pokemon, _defender, move)) &&
!noAbilityTypeOverrideMoves.has(move.id) && !noAbilityTypeOverrideMoves.has(move.id) &&
(!pokemon.isTerastallized || (!pokemon.isTerastallized ||
(move.id !== MoveId.TERA_BLAST && (move.id !== MoveId.TERA_BLAST &&
(move.id !== MoveId.TERA_STARSTORM || pokemon.getTeraType() !== PokemonType.STELLAR || !pokemon.hasSpecies(SpeciesId.TERAPAGOS)))); (move.id !== MoveId.TERA_STARSTORM || pokemon.getTeraType() !== PokemonType.STELLAR || !pokemon.hasSpecies(SpeciesId.TERAPAGOS))));
@ -2617,7 +2617,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt
} }
override canApplyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { override canApplyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
const party = pokemon instanceof PlayerPokemon ? globalScene.getPlayerField() : globalScene.getEnemyField(); const party = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
return party.filter(p => p.isAllowedInBattle()).length > 0; return party.filter(p => p.isAllowedInBattle()).length > 0;
} }
@ -2629,7 +2629,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt
* @param args - n/a * @param args - n/a
*/ */
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
const party = pokemon instanceof PlayerPokemon ? globalScene.getPlayerField() : globalScene.getEnemyField(); const party = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
const allowedParty = party.filter(p => p.isAllowedInBattle()); const allowedParty = party.filter(p => p.isAllowedInBattle());
if (!simulated) { if (!simulated) {
@ -2653,11 +2653,7 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr {
} }
const ally = pokemon.getAlly(); const ally = pokemon.getAlly();
if (isNullOrUndefined(ally) || ally.getStatStages().every(s => s === 0)) { return !(isNullOrUndefined(ally) || ally.getStatStages().every(s => s === 0));
return false;
}
return true;
} }
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
@ -2723,11 +2719,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
} }
// transforming from or into fusion pokemon causes various problems (including crashes and save corruption) // transforming from or into fusion pokemon causes various problems (including crashes and save corruption)
if (this.getTarget(targets).fusionSpecies || pokemon.fusionSpecies) { return !(this.getTarget(targets).fusionSpecies || pokemon.fusionSpecies);
return false;
}
return true;
} }
override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void { override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void {
@ -2828,7 +2820,7 @@ export class CommanderAbAttr extends AbAttr {
// Apply boosts from this effect to the ally Dondozo // Apply boosts from this effect to the ally Dondozo
pokemon.getAlly()?.addTag(BattlerTagType.COMMANDED, 0, MoveId.NONE, pokemon.id); pokemon.getAlly()?.addTag(BattlerTagType.COMMANDED, 0, MoveId.NONE, pokemon.id);
// Cancel the source Pokemon's next move (if a move is queued) // Cancel the source Pokemon's next move (if a move is queued)
globalScene.tryRemovePhase((phase) => phase instanceof MovePhase && phase.pokemon === pokemon); globalScene.tryRemovePhase((phase) => phase.is("MovePhase") && phase.pokemon === pokemon);
} }
} }
} }
@ -3544,10 +3536,7 @@ export class BlockStatusDamageAbAttr extends AbAttr {
} }
override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { override canApply(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
if (pokemon.status && this.effects.includes(pokemon.status.effect)) { return !!pokemon.status?.effect && this.effects.includes(pokemon.status.effect);
return true;
}
return false;
} }
/** /**
@ -4449,6 +4438,7 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
simulated: boolean, simulated: boolean,
args: any[]): void { args: any[]): void {
if (!simulated) { if (!simulated) {
dancer.turnData.extraTurns++;
// If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance // If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance
if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) { if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
const target = this.getTarget(dancer, source, targets); const target = this.getTarget(dancer, source, targets);
@ -4803,11 +4793,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
const diedToDirectDamage = move !== undefined && attacker !== undefined && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}); const diedToDirectDamage = move !== undefined && attacker !== undefined && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon});
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
globalScene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated)); globalScene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
if (!diedToDirectDamage || cancelled.value || attacker!.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { return !(!diedToDirectDamage || cancelled.value || attacker!.hasAbilityWithAttr(BlockNonDirectDamageAbAttr));
return false;
}
return true;
} }
override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void { override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void {
@ -5553,7 +5539,7 @@ class ForceSwitchOutHelper {
* - Whether there are available party members to switch in. * - Whether there are available party members to switch in.
* - If the Pokémon is still alive (hp > 0), and if so, it leaves the field and a new SwitchPhase is initiated. * - If the Pokémon is still alive (hp > 0), and if so, it leaves the field and a new SwitchPhase is initiated.
*/ */
if (switchOutTarget instanceof PlayerPokemon) { if (switchOutTarget.isPlayer()) {
if (globalScene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) { if (globalScene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) {
return false; return false;
} }
@ -5622,7 +5608,7 @@ class ForceSwitchOutHelper {
*/ */
public getSwitchOutCondition(pokemon: Pokemon, opponent: Pokemon): boolean { public getSwitchOutCondition(pokemon: Pokemon, opponent: Pokemon): boolean {
const switchOutTarget = pokemon; const switchOutTarget = pokemon;
const player = switchOutTarget instanceof PlayerPokemon; const player = switchOutTarget.isPlayer();
if (player) { if (player) {
const blockedByAbility = new BooleanHolder(false); const blockedByAbility = new BooleanHolder(false);
@ -6508,12 +6494,7 @@ export function initAbilities() {
new Ability(AbilityId.INTIMIDATE, 3) new Ability(AbilityId.INTIMIDATE, 3)
.attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], -1, false, true), .attr(PostSummonStatStageChangeAbAttr, [ Stat.ATK ], -1, false, true),
new Ability(AbilityId.SHADOW_TAG, 3) new Ability(AbilityId.SHADOW_TAG, 3)
.attr(ArenaTrapAbAttr, (user, target) => { .attr(ArenaTrapAbAttr, (_user, target) => !target.hasAbility(AbilityId.SHADOW_TAG)),
if (target.hasAbility(AbilityId.SHADOW_TAG)) {
return false;
}
return true;
}),
new Ability(AbilityId.ROUGH_SKIN, 3) new Ability(AbilityId.ROUGH_SKIN, 3)
.attr(PostDefendContactDamageAbAttr, 8) .attr(PostDefendContactDamageAbAttr, 8)
.bypassFaint(), .bypassFaint(),
@ -6573,10 +6554,7 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(AbilityId.MAGNET_PULL, 3) new Ability(AbilityId.MAGNET_PULL, 3)
.attr(ArenaTrapAbAttr, (user, target) => { .attr(ArenaTrapAbAttr, (user, target) => {
if (target.getTypes(true).includes(PokemonType.STEEL) || (target.getTypes(true).includes(PokemonType.STELLAR) && target.getTypes().includes(PokemonType.STEEL))) { return target.getTypes(true).includes(PokemonType.STEEL) || (target.getTypes(true).includes(PokemonType.STELLAR) && target.getTypes().includes(PokemonType.STEEL));
return true;
}
return false;
}), }),
new Ability(AbilityId.SOUNDPROOF, 3) new Ability(AbilityId.SOUNDPROOF, 3)
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.SOUND_BASED)) .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.hasFlag(MoveFlags.SOUND_BASED))
@ -6654,12 +6632,7 @@ export function initAbilities() {
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SUNNY) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SUNNY)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SUNNY), .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SUNNY),
new Ability(AbilityId.ARENA_TRAP, 3) new Ability(AbilityId.ARENA_TRAP, 3)
.attr(ArenaTrapAbAttr, (user, target) => { .attr(ArenaTrapAbAttr, (user, target) => target.isGrounded())
if (target.isGrounded()) {
return true;
}
return false;
})
.attr(DoubleBattleChanceAbAttr), .attr(DoubleBattleChanceAbAttr),
new Ability(AbilityId.VITAL_SPIRIT, 3) new Ability(AbilityId.VITAL_SPIRIT, 3)
.attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP)
@ -6897,7 +6870,7 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(AbilityId.ANALYTIC, 5) new Ability(AbilityId.ANALYTIC, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => { .attr(MovePowerBoostAbAttr, (user, target, move) => {
const movePhase = globalScene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.id !== user?.id); const movePhase = globalScene.findPhase((phase) => phase.is("MovePhase") && phase.pokemon.id !== user?.id);
return isNullOrUndefined(movePhase); return isNullOrUndefined(movePhase);
}, 1.3), }, 1.3),
new Ability(AbilityId.ILLUSION, 5) new Ability(AbilityId.ILLUSION, 5)

View File

@ -383,7 +383,7 @@ const QuickGuardConditionFunc: ProtectConditionFunc = (_arena, moveId) => {
const move = allMoves[moveId]; const move = allMoves[moveId];
const effectPhase = globalScene.getCurrentPhase(); const effectPhase = globalScene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase) { if (effectPhase?.is("MoveEffectPhase")) {
const attacker = effectPhase.getUserPokemon(); const attacker = effectPhase.getUserPokemon();
if (attacker) { if (attacker) {
return move.getPriority(attacker) > 0; return move.getPriority(attacker) > 0;

View File

@ -28,7 +28,7 @@ import type Pokemon from "#app/field/pokemon";
import { HitResult, MoveResult } from "#app/field/pokemon"; import { HitResult, MoveResult } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MovePhase } from "#app/phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
@ -553,9 +553,9 @@ export class ShellTrapTag extends BattlerTag {
// Trap should only be triggered by opponent's Physical moves // Trap should only be triggered by opponent's Physical moves
if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponent(phaseData.attacker)) { if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponent(phaseData.attacker)) {
const shellTrapPhaseIndex = globalScene.phaseQueue.findIndex( const shellTrapPhaseIndex = globalScene.phaseQueue.findIndex(
phase => phase instanceof MovePhase && phase.pokemon === pokemon, phase => phase.is("MovePhase") && phase.pokemon === pokemon,
); );
const firstMovePhaseIndex = globalScene.phaseQueue.findIndex(phase => phase instanceof MovePhase); const firstMovePhaseIndex = globalScene.phaseQueue.findIndex(phase => phase.is("MovePhase"));
// Only shift MovePhase timing if it's not already next up // Only shift MovePhase timing if it's not already next up
if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) {
@ -649,20 +649,14 @@ class NoRetreatTag extends TrappedTag {
*/ */
export class FlinchedTag extends BattlerTag { export class FlinchedTag extends BattlerTag {
constructor(sourceMove: MoveId) { constructor(sourceMove: MoveId) {
super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 0, sourceMove); super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 1, sourceMove);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
applyAbAttrs(FlinchEffectAbAttr, pokemon, null);
} }
/** /**
* Cancels the Pokemon's next Move on the turn this tag is applied * Cancels the flinched Pokemon's currently used move this turn if called mid-execution, or removes the tag at end of turn.
* @param pokemon The {@linkcode Pokemon} with this tag * @param pokemon - The {@linkcode Pokemon} with this tag.
* @param lapseType The {@linkcode BattlerTagLapseType lapse type} used for this function call * @param lapseType - The {@linkcode BattlerTagLapseType | lapse type} used for this function call.
* @returns `false` (This tag is always removed after applying its effects) * @returns Whether the tag should remain active.
*/ */
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) { if (lapseType === BattlerTagLapseType.PRE_MOVE) {
@ -672,6 +666,8 @@ export class FlinchedTag extends BattlerTag {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
applyAbAttrs(FlinchEffectAbAttr, pokemon, null);
return true;
} }
return super.lapse(pokemon, lapseType); return super.lapse(pokemon, lapseType);
@ -1027,7 +1023,7 @@ export class PowderTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) { if (lapseType === BattlerTagLapseType.PRE_MOVE) {
const movePhase = globalScene.getCurrentPhase(); const movePhase = globalScene.getCurrentPhase();
if (movePhase instanceof MovePhase) { if (movePhase?.is("MovePhase")) {
const move = movePhase.move.getMove(); const move = movePhase.move.getMove();
const weather = globalScene.arena.weather; const weather = globalScene.arena.weather;
if ( if (
@ -1183,13 +1179,13 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
}), }),
); );
const movePhase = globalScene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon); const movePhase = globalScene.findPhase(m => m.is("MovePhase") && m.pokemon === pokemon);
if (movePhase) { if (movePhase) {
const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId); const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId);
if (movesetMove) { if (movesetMove) {
const lastMove = pokemon.getLastXMoves(1)[0]; const lastMove = pokemon.getLastXMoves(1)[0];
globalScene.tryReplacePhase( globalScene.tryReplacePhase(
m => m instanceof MovePhase && m.pokemon === pokemon, m => m.is("MovePhase") && m.pokemon === pokemon,
new MovePhase(pokemon, lastMove.targets ?? [], movesetMove), new MovePhase(pokemon, lastMove.targets ?? [], movesetMove),
); );
} }
@ -1203,10 +1199,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) { if (lapseType === BattlerTagLapseType.CUSTOM) {
const encoredMove = pokemon.getMoveset().find(m => m.moveId === this.moveId); const encoredMove = pokemon.getMoveset().find(m => m.moveId === this.moveId);
if (encoredMove && encoredMove?.getPpRatio() > 0) { return !isNullOrUndefined(encoredMove) && encoredMove.getPpRatio() > 0;
return true;
}
return false;
} }
return super.lapse(pokemon, lapseType); return super.lapse(pokemon, lapseType);
} }
@ -1218,10 +1211,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
* @returns `true` if the move does not match with the moveId stored and as a result, restricted * @returns `true` if the move does not match with the moveId stored and as a result, restricted
*/ */
override isMoveRestricted(move: MoveId, _user?: Pokemon): boolean { override isMoveRestricted(move: MoveId, _user?: Pokemon): boolean {
if (move !== this.moveId) { return move !== this.moveId;
return true;
}
return false;
} }
override selectionDeniedText(_pokemon: Pokemon, move: MoveId): string { override selectionDeniedText(_pokemon: Pokemon, move: MoveId): string {
@ -1624,7 +1614,7 @@ export class ProtectedTag extends BattlerTag {
// Stop multi-hit moves early // Stop multi-hit moves early
const effectPhase = globalScene.getCurrentPhase(); const effectPhase = globalScene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase) { if (effectPhase?.is("MoveEffectPhase")) {
effectPhase.stopMultiHit(pokemon); effectPhase.stopMultiHit(pokemon);
} }
return true; return true;
@ -2646,7 +2636,7 @@ export class GulpMissileTag extends BattlerTag {
} }
const moveEffectPhase = globalScene.getCurrentPhase(); const moveEffectPhase = globalScene.getCurrentPhase();
if (moveEffectPhase instanceof MoveEffectPhase) { if (moveEffectPhase?.is("MoveEffectPhase")) {
const attacker = moveEffectPhase.getUserPokemon(); const attacker = moveEffectPhase.getUserPokemon();
if (!attacker) { if (!attacker) {
@ -2768,10 +2758,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
* @returns `true` if the move has a TRIAGE_MOVE flag and is a status move * @returns `true` if the move has a TRIAGE_MOVE flag and is a status move
*/ */
override isMoveRestricted(move: MoveId): boolean { override isMoveRestricted(move: MoveId): boolean {
if (allMoves[move].hasFlag(MoveFlags.TRIAGE_MOVE) && allMoves[move].category === MoveCategory.STATUS) { return allMoves[move].hasFlag(MoveFlags.TRIAGE_MOVE) && allMoves[move].category === MoveCategory.STATUS;
return true;
}
return false;
} }
/** /**
@ -2785,10 +2772,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
override isMoveTargetRestricted(move: MoveId, user: Pokemon, target: Pokemon) { override isMoveTargetRestricted(move: MoveId, user: Pokemon, target: Pokemon) {
const moveCategory = new NumberHolder(allMoves[move].category); const moveCategory = new NumberHolder(allMoves[move].category);
applyMoveAttrs(StatusCategoryOnAllyAttr, user, target, allMoves[move], moveCategory); applyMoveAttrs(StatusCategoryOnAllyAttr, user, target, allMoves[move], moveCategory);
if (allMoves[move].hasAttr(HealOnAllyAttr) && moveCategory.value === MoveCategory.STATUS) { return allMoves[move].hasAttr(HealOnAllyAttr) && moveCategory.value === MoveCategory.STATUS;
return true;
}
return false;
} }
/** /**
@ -3004,7 +2988,7 @@ export class SubstituteTag extends BattlerTag {
/** If the Substitute redirects damage, queue a message to indicate it. */ /** If the Substitute redirects damage, queue a message to indicate it. */
onHit(pokemon: Pokemon): void { onHit(pokemon: Pokemon): void {
const moveEffectPhase = globalScene.getCurrentPhase(); const moveEffectPhase = globalScene.getCurrentPhase();
if (moveEffectPhase instanceof MoveEffectPhase) { if (moveEffectPhase?.is("MoveEffectPhase")) {
const attacker = moveEffectPhase.getUserPokemon(); const attacker = moveEffectPhase.getUserPokemon();
if (!attacker) { if (!attacker) {
return; return;
@ -3126,10 +3110,7 @@ export class TormentTag extends MoveRestrictionBattlerTag {
const moveObj = allMoves[lastMove.move]; const moveObj = allMoves[lastMove.move];
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY); const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY);
const validLastMoveResult = lastMove.result === MoveResult.SUCCESS || lastMove.result === MoveResult.MISS; const validLastMoveResult = lastMove.result === MoveResult.SUCCESS || lastMove.result === MoveResult.MISS;
if (lastMove.move === move && validLastMoveResult && lastMove.move !== MoveId.STRUGGLE && !isUnaffected) { return lastMove.move === move && validLastMoveResult && lastMove.move !== MoveId.STRUGGLE && !isUnaffected;
return true;
}
return false;
} }
override selectionDeniedText(pokemon: Pokemon, _move: MoveId): string { override selectionDeniedText(pokemon: Pokemon, _move: MoveId): string {
@ -3693,7 +3674,7 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag {
*/ */
function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; attacker: Pokemon; move: Move } | null { function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; attacker: Pokemon; move: Move } | null {
const phase = globalScene.getCurrentPhase(); const phase = globalScene.getCurrentPhase();
if (phase instanceof MoveEffectPhase) { if (phase?.is("MoveEffectPhase")) {
return { return {
phase: phase, phase: phase,
attacker: phase.getPokemon(), attacker: phase.getPokemon(),

View File

@ -1,6 +1,7 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import type { DexEntry, StarterDataEntry } from "#app/system/game-data"; import type { StarterDataEntry } from "#app/system/game-data";
import type { DexEntry } from "#app/@types/dex-data";
/** /**
* Stores data associated with a specific egg and the hatched pokemon * Stores data associated with a specific egg and the hatched pokemon

View File

@ -81,7 +81,7 @@ import { TerrainType } from "../terrain";
import { ModifierPoolType } from "#app/modifier/modifier-type"; import { ModifierPoolType } from "#app/modifier/modifier-type";
import { Command } from "../../ui/command-ui-handler"; import { Command } from "../../ui/command-ui-handler";
import i18next from "i18next"; import i18next from "i18next";
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/@types/locales";
import { getBerryEffectFunc } from "../berry"; import { getBerryEffectFunc } from "../berry";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
@ -837,7 +837,7 @@ export default class Move implements Localizable {
aura.applyPreAttack(source, null, simulated, target, this, [ power ]); aura.applyPreAttack(source, null, simulated, target, this, [ power ]);
} }
const alliedField: Pokemon[] = source instanceof PlayerPokemon ? globalScene.getPlayerField() : globalScene.getEnemyField(); const alliedField: Pokemon[] = source.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power)); alliedField.forEach(p => applyPreAttackAbAttrs(UserFieldMoveTypePowerBoostAbAttr, p, target, this, simulated, power));
power.value *= typeChangeMovePowerMultiplier.value; power.value *= typeChangeMovePowerMultiplier.value;
@ -3109,7 +3109,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
const overridden = args[0] as BooleanHolder; const overridden = args[0] as BooleanHolder;
const allyMovePhase = globalScene.findPhase<MovePhase>((phase) => phase instanceof MovePhase && phase.pokemon.isPlayer() === user.isPlayer()); const allyMovePhase = globalScene.findPhase<MovePhase>((phase) => phase.is("MovePhase") && phase.pokemon.isPlayer() === user.isPlayer());
if (allyMovePhase) { if (allyMovePhase) {
const allyMove = allyMovePhase.move.getMove(); const allyMove = allyMovePhase.move.getMove();
if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) { if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) {
@ -3123,7 +3123,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
// Move the ally's MovePhase (if needed) so that the ally moves next // Move the ally's MovePhase (if needed) so that the ally moves next
const allyMovePhaseIndex = globalScene.phaseQueue.indexOf(allyMovePhase); const allyMovePhaseIndex = globalScene.phaseQueue.indexOf(allyMovePhase);
const firstMovePhaseIndex = globalScene.phaseQueue.findIndex((phase) => phase instanceof MovePhase); const firstMovePhaseIndex = globalScene.phaseQueue.findIndex((phase) => phase.is("MovePhase"));
if (allyMovePhaseIndex !== firstMovePhaseIndex) { if (allyMovePhaseIndex !== firstMovePhaseIndex) {
globalScene.prependToPhase(globalScene.phaseQueue.splice(allyMovePhaseIndex, 1)[0], MovePhase); globalScene.prependToPhase(globalScene.phaseQueue.splice(allyMovePhaseIndex, 1)[0], MovePhase);
} }
@ -4125,7 +4125,7 @@ export class FriendshipPowerAttr extends VariablePowerAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const power = args[0] as NumberHolder; const power = args[0] as NumberHolder;
const friendshipPower = Math.floor(Math.min(user instanceof PlayerPokemon ? user.friendship : user.species.baseFriendship, 255) / 2.5); const friendshipPower = Math.floor(Math.min(user.isPlayer() ? user.friendship : user.species.baseFriendship, 255) / 2.5);
power.value = Math.max(!this.invert ? friendshipPower : 102 - friendshipPower, 1); power.value = Math.max(!this.invert ? friendshipPower : 102 - friendshipPower, 1);
return true; return true;
@ -4477,7 +4477,7 @@ export class CueNextRoundAttr extends MoveEffectAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
const nextRoundPhase = globalScene.findPhase<MovePhase>(phase => const nextRoundPhase = globalScene.findPhase<MovePhase>(phase =>
phase instanceof MovePhase && phase.move.moveId === MoveId.ROUND phase.is("MovePhase") && phase.move.moveId === MoveId.ROUND
); );
if (!nextRoundPhase) { if (!nextRoundPhase) {
@ -4486,7 +4486,7 @@ export class CueNextRoundAttr extends MoveEffectAttr {
// Update the phase queue so that the next Pokemon using Round moves next // Update the phase queue so that the next Pokemon using Round moves next
const nextRoundIndex = globalScene.phaseQueue.indexOf(nextRoundPhase); const nextRoundIndex = globalScene.phaseQueue.indexOf(nextRoundPhase);
const nextMoveIndex = globalScene.phaseQueue.findIndex(phase => phase instanceof MovePhase); const nextMoveIndex = globalScene.phaseQueue.findIndex(phase => phase.is("MovePhase"));
if (nextRoundIndex !== nextMoveIndex) { if (nextRoundIndex !== nextMoveIndex) {
globalScene.prependToPhase(globalScene.phaseQueue.splice(nextRoundIndex, 1)[0], MovePhase); globalScene.prependToPhase(globalScene.phaseQueue.splice(nextRoundIndex, 1)[0], MovePhase);
} }
@ -5472,13 +5472,6 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
this.failOnOverlap = !!failOnOverlap; this.failOnOverlap = !!failOnOverlap;
} }
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.canApply(user, target, move, args)) {
return false;
}
return true;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args)) { if (!super.apply(user, target, move, args)) {
return false; return false;
@ -6156,14 +6149,14 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
* @param target {@linkcode Pokemon} target of this move * @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used * @param move {@linkcode Move} being used
* @param args N/A * @param args N/A
* @returns Promise, true if function succeeds. * @returns `true` if function succeeds.
*/ */
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
// If user is player, checks if the user has fainted pokemon // If user is player, checks if the user has fainted pokemon
if (user instanceof PlayerPokemon) { if (user.isPlayer()) {
globalScene.unshiftPhase(new RevivalBlessingPhase(user)); globalScene.unshiftPhase(new RevivalBlessingPhase(user));
return true; return true;
} else if (user instanceof EnemyPokemon && user.hasTrainer() && globalScene.getEnemyParty().findIndex((p) => p.isFainted() && !p.isBoss()) > -1) { } else if (user.isEnemy() && user.hasTrainer() && globalScene.getEnemyParty().findIndex((p) => p.isFainted() && !p.isBoss()) > -1) {
// If used by an enemy trainer with at least one fainted non-boss Pokemon, this // If used by an enemy trainer with at least one fainted non-boss Pokemon, this
// revives one of said Pokemon selected at random. // revives one of said Pokemon selected at random.
const faintedPokemon = globalScene.getEnemyParty().filter((p) => p.isFainted() && !p.isBoss()); const faintedPokemon = globalScene.getEnemyParty().filter((p) => p.isFainted() && !p.isBoss());
@ -6177,7 +6170,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
// Handle cases where revived pokemon needs to get switched in on same turn // Handle cases where revived pokemon needs to get switched in on same turn
if (allyPokemon.isFainted() || allyPokemon === pokemon) { if (allyPokemon.isFainted() || allyPokemon === pokemon) {
// Enemy switch phase should be removed and replaced with the revived pkmn switching in // Enemy switch phase should be removed and replaced with the revived pkmn switching in
globalScene.tryRemovePhase((phase: SwitchSummonPhase) => phase instanceof SwitchSummonPhase && phase.getPokemon() === pokemon); globalScene.tryRemovePhase((phase: SwitchSummonPhase) => phase.is("SwitchSummonPhase") && phase.getPokemon() === pokemon);
// If the pokemon being revived was alive earlier in the turn, cancel its move // If the pokemon being revived was alive earlier in the turn, cancel its move
// (revived pokemon can't move in the turn they're brought back) // (revived pokemon can't move in the turn they're brought back)
globalScene.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel(); globalScene.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel();
@ -6194,10 +6187,8 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user, target, move) => return (user, target, move) =>
(user instanceof PlayerPokemon && globalScene.getPlayerParty().some((p) => p.isFainted())) || user.hasTrainer() &&
(user instanceof EnemyPokemon && (user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty()).some((p: Pokemon) => p.isFainted() && !p.isBoss());
user.hasTrainer() &&
globalScene.getEnemyParty().some((p) => p.isFainted() && !p.isBoss()));
} }
override getUserBenefitScore(user: Pokemon, _target: Pokemon, _move: Move): number { override getUserBenefitScore(user: Pokemon, _target: Pokemon, _move: Move): number {
@ -6235,7 +6226,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
// (e.g. when it uses Flip Turn), make it spit out the Tatsugiri before switching out. // (e.g. when it uses Flip Turn), make it spit out the Tatsugiri before switching out.
switchOutTarget.lapseTag(BattlerTagType.COMMANDED); switchOutTarget.lapseTag(BattlerTagType.COMMANDED);
if (switchOutTarget instanceof PlayerPokemon) { if (switchOutTarget.isPlayer()) {
/** /**
* Check if Wimp Out/Emergency Exit activates due to being hit by U-turn or Volt Switch * Check if Wimp Out/Emergency Exit activates due to being hit by U-turn or Volt Switch
* If it did, the user of U-turn or Volt Switch will not be switched out. * If it did, the user of U-turn or Volt Switch will not be switched out.
@ -6389,7 +6380,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
getSwitchOutCondition(): MoveConditionFunc { getSwitchOutCondition(): MoveConditionFunc {
return (user, target, move) => { return (user, target, move) => {
const switchOutTarget = (this.selfSwitch ? user : target); const switchOutTarget = (this.selfSwitch ? user : target);
const player = switchOutTarget instanceof PlayerPokemon; const player = switchOutTarget.isPlayer();
const forceSwitchAttr = move.getAttrs(ForceSwitchOutAttr).find(attr => attr.switchType === SwitchType.FORCE_SWITCH); const forceSwitchAttr = move.getAttrs(ForceSwitchOutAttr).find(attr => attr.switchType === SwitchType.FORCE_SWITCH);
if (!this.selfSwitch) { if (!this.selfSwitch) {
@ -6832,7 +6823,7 @@ export class RandomMovesetMoveAttr extends CallMoveAttr {
return false; return false;
} }
this.moveId = moves[user.randBattleSeedInt(moves.length)]!.moveId; this.moveId = moves[user.randBattleSeedInt(moves.length)].moveId;
return true; return true;
}; };
} }
@ -7367,11 +7358,7 @@ export class SketchAttr extends MoveEffectAttr {
return false; return false;
} }
if (user.getMoveset().find(m => m.moveId === targetMove.move)) { return !user.getMoveset().some(m => m.moveId === targetMove.move);
return false;
}
return true;
}; };
} }
} }
@ -7896,7 +7883,7 @@ export class ForceLastAttr extends MoveEffectAttr {
// Either the end of the turn or in front of another, slower move which has also been forced last // Either the end of the turn or in front of another, slower move which has also been forced last
const prependPhase = globalScene.findPhase((phase) => const prependPhase = globalScene.findPhase((phase) =>
[ MovePhase, MoveEndPhase ].every(cls => !(phase instanceof cls)) [ MovePhase, MoveEndPhase ].every(cls => !(phase instanceof cls))
|| (phase instanceof MovePhase) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM)) || (phase.is("MovePhase")) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM))
); );
if (prependPhase) { if (prependPhase) {
globalScene.phaseQueue.splice( globalScene.phaseQueue.splice(
@ -7942,7 +7929,7 @@ const userSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target:
const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(AbilityId.COMATOSE); const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(AbilityId.COMATOSE);
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseQueue.find(phase => phase instanceof MovePhase) !== undefined; const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseQueue.find(phase => phase.is("MovePhase")) !== undefined;
const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => { const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
@ -9868,7 +9855,7 @@ export function initMoves() {
const lastEnemyFaint = globalScene.currentBattle.enemyFaintsHistory[globalScene.currentBattle.enemyFaintsHistory.length - 1]; const lastEnemyFaint = globalScene.currentBattle.enemyFaintsHistory[globalScene.currentBattle.enemyFaintsHistory.length - 1];
return ( return (
(lastPlayerFaint !== undefined && turn - lastPlayerFaint.turn === 1 && user.isPlayer()) || (lastPlayerFaint !== undefined && turn - lastPlayerFaint.turn === 1 && user.isPlayer()) ||
(lastEnemyFaint !== undefined && turn - lastEnemyFaint.turn === 1 && !user.isPlayer()) (lastEnemyFaint !== undefined && turn - lastEnemyFaint.turn === 1 && user.isEnemy())
) ? 2 : 1; ) ? 2 : 1;
}), }),
new AttackMove(MoveId.FINAL_GAMBIT, PokemonType.FIGHTING, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 5) new AttackMove(MoveId.FINAL_GAMBIT, PokemonType.FIGHTING, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 5)

View File

@ -33,7 +33,7 @@ import {
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import type { BerryType } from "#enums/berry-type"; import type { BerryType } from "#enums/berry-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";

View File

@ -25,7 +25,7 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import i18next from "i18next"; import i18next from "i18next";
import { getStatKey } from "#enums/stat"; import { getStatKey } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";

View File

@ -39,7 +39,7 @@ import { PlayerGender } from "#enums/player-gender";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import { trainerConfigs } from "#app/data/trainers/trainer-config"; import { trainerConfigs } from "#app/data/trainers/trainer-config";
import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate"; import { TrainerPartyTemplate } from "#app/data/trainers/TrainerPartyTemplate";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";

View File

@ -275,15 +275,11 @@ export class TimeOfDayRequirement extends EncounterSceneRequirement {
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
const timeOfDay = globalScene.arena?.getTimeOfDay(); const timeOfDay = globalScene.arena?.getTimeOfDay();
if ( return !(
!isNullOrUndefined(timeOfDay) && !isNullOrUndefined(timeOfDay) &&
this.requiredTimeOfDay?.length > 0 && this.requiredTimeOfDay?.length > 0 &&
!this.requiredTimeOfDay.includes(timeOfDay) !this.requiredTimeOfDay.includes(timeOfDay)
) { );
return false;
}
return true;
} }
override getDialogueToken(_pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(_pokemon?: PlayerPokemon): [string, string] {
@ -301,15 +297,11 @@ export class WeatherRequirement extends EncounterSceneRequirement {
override meetsRequirement(): boolean { override meetsRequirement(): boolean {
const currentWeather = globalScene.arena.weather?.weatherType; const currentWeather = globalScene.arena.weather?.weatherType;
if ( return !(
!isNullOrUndefined(currentWeather) && !isNullOrUndefined(currentWeather) &&
this.requiredWeather?.length > 0 && this.requiredWeather?.length > 0 &&
!this.requiredWeather.includes(currentWeather!) !this.requiredWeather.includes(currentWeather!)
) { );
return false;
}
return true;
} }
override getDialogueToken(_pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(_pokemon?: PlayerPokemon): [string, string] {
@ -803,7 +795,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
} }
filterByForm(pokemon, formChangeItem) { filterByForm(pokemon, formChangeItem) {
if ( return (
pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) && pokemonFormChanges.hasOwnProperty(pokemon.species.speciesId) &&
// Get all form changes for this species with an item trigger, including any compound triggers // Get all form changes for this species with an item trigger, including any compound triggers
pokemonFormChanges[pokemon.species.speciesId] pokemonFormChanges[pokemon.species.speciesId]
@ -812,10 +804,7 @@ export class CanFormChangeWithItemRequirement extends EncounterPokemonRequiremen
.flatMap(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger) .flatMap(fc => fc.findTrigger(SpeciesFormChangeItemTrigger) as SpeciesFormChangeItemTrigger)
.flatMap(fc => fc.item) .flatMap(fc => fc.item)
.includes(formChangeItem) .includes(formChangeItem)
) { );
return true;
}
return false;
} }
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
@ -873,17 +862,15 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
) { ) {
return true; return true;
} }
if (
return (
pokemon.isFusion() && pokemon.isFusion() &&
pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) &&
pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter( pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(
e => e.item === evolutionItem && (!e.condition || e.condition.predicate(pokemon)), e => e.item === evolutionItem && (!e.condition || e.condition.predicate(pokemon)),
).length && ).length &&
pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX
) { );
return true;
}
return false;
} }
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {

View File

@ -50,7 +50,7 @@ import type PokemonSpecies from "#app/data/pokemon-species";
import type { IEggOptions } from "#app/data/egg"; import type { IEggOptions } from "#app/data/egg";
import { Egg } from "#app/data/egg"; import { Egg } from "#app/data/egg";
import type { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { CustomPokemonData } from "#app/data/custom-pokemon-data";
import type HeldModifierConfig from "#app/interfaces/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import { MovePhase } from "#app/phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { EggLapsePhase } from "#app/phases/egg-lapse-phase"; import { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase"; import { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
@ -769,7 +769,7 @@ export function setEncounterRewards(
if (customShopRewards) { if (customShopRewards) {
globalScene.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards)); globalScene.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards));
} else { } else {
globalScene.tryRemovePhase(p => p instanceof SelectModifierPhase); globalScene.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase"));
} }
if (eggRewards) { if (eggRewards) {

View File

@ -186,11 +186,7 @@ export class SpeciesFormChange {
} }
} }
if (!this.trigger.canChange(pokemon)) { return this.trigger.canChange(pokemon);
return false;
}
return true;
} }
findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | nil { findTrigger(triggerType: Constructor<SpeciesFormChangeTrigger>): SpeciesFormChangeTrigger | nil {

View File

@ -1,4 +1,4 @@
import type { Localizable } from "#app/interfaces/locales"; import type { Localizable } from "#app/@types/locales";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { PartyMemberStrength } from "#enums/party-member-strength"; import { PartyMemberStrength } from "#enums/party-member-strength";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
@ -1281,10 +1281,6 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali
}; };
} }
isObtainable() {
return super.isObtainable();
}
hasVariants() { hasVariants() {
let variantDataIndex: string | number = this.speciesId; let variantDataIndex: string | number = this.speciesId;
if (this.forms.length > 0) { if (this.forms.length > 0) {
@ -2026,9 +2022,9 @@ export function initSpecies() {
new PokemonForm("Normal", "", PokemonType.GROUND, null, 3.5, 950, AbilityId.DROUGHT, AbilityId.NONE, AbilityId.NONE, 670, 100, 150, 140, 100, 90, 90, 3, 0, 335, false, null, true), new PokemonForm("Normal", "", PokemonType.GROUND, null, 3.5, 950, AbilityId.DROUGHT, AbilityId.NONE, AbilityId.NONE, 670, 100, 150, 140, 100, 90, 90, 3, 0, 335, false, null, true),
new PokemonForm("Primal", "primal", PokemonType.GROUND, PokemonType.FIRE, 5, 999.7, AbilityId.DESOLATE_LAND, AbilityId.NONE, AbilityId.NONE, 770, 100, 180, 160, 150, 90, 90, 3, 0, 335), new PokemonForm("Primal", "primal", PokemonType.GROUND, PokemonType.FIRE, 5, 999.7, AbilityId.DESOLATE_LAND, AbilityId.NONE, AbilityId.NONE, 770, 100, 180, 160, 150, 90, 90, 3, 0, 335),
), ),
new PokemonSpecies(SpeciesId.RAYQUAZA, 3, false, true, false, "Sky High Pokémon", PokemonType.DRAGON, PokemonType.FLYING, 7, 206.5, AbilityId.AIR_LOCK, AbilityId.NONE, AbilityId.NONE, 680, 105, 150, 90, 150, 90, 95, 45, 0, 340, GrowthRate.SLOW, null, false, true, new PokemonSpecies(SpeciesId.RAYQUAZA, 3, false, true, false, "Sky High Pokémon", PokemonType.DRAGON, PokemonType.FLYING, 7, 206.5, AbilityId.AIR_LOCK, AbilityId.NONE, AbilityId.NONE, 680, 105, 150, 90, 150, 90, 95, 3, 0, 340, GrowthRate.SLOW, null, false, true,
new PokemonForm("Normal", "", PokemonType.DRAGON, PokemonType.FLYING, 7, 206.5, AbilityId.AIR_LOCK, AbilityId.NONE, AbilityId.NONE, 680, 105, 150, 90, 150, 90, 95, 45, 0, 340, false, null, true), new PokemonForm("Normal", "", PokemonType.DRAGON, PokemonType.FLYING, 7, 206.5, AbilityId.AIR_LOCK, AbilityId.NONE, AbilityId.NONE, 680, 105, 150, 90, 150, 90, 95, 3, 0, 340, false, null, true),
new PokemonForm("Mega", SpeciesFormKey.MEGA, PokemonType.DRAGON, PokemonType.FLYING, 10.8, 392, AbilityId.DELTA_STREAM, AbilityId.NONE, AbilityId.NONE, 780, 105, 180, 100, 180, 100, 115, 45, 0, 340), new PokemonForm("Mega", SpeciesFormKey.MEGA, PokemonType.DRAGON, PokemonType.FLYING, 10.8, 392, AbilityId.DELTA_STREAM, AbilityId.NONE, AbilityId.NONE, 780, 105, 180, 100, 180, 100, 115, 3, 0, 340),
), ),
new PokemonSpecies(SpeciesId.JIRACHI, 3, false, false, true, "Wish Pokémon", PokemonType.STEEL, PokemonType.PSYCHIC, 0.3, 1.1, AbilityId.SERENE_GRACE, AbilityId.NONE, AbilityId.NONE, 600, 100, 100, 100, 100, 100, 100, 3, 100, 300, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.JIRACHI, 3, false, false, true, "Wish Pokémon", PokemonType.STEEL, PokemonType.PSYCHIC, 0.3, 1.1, AbilityId.SERENE_GRACE, AbilityId.NONE, AbilityId.NONE, 600, 100, 100, 100, 100, 100, 100, 3, 100, 300, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.DEOXYS, 3, false, false, true, "DNA Pokémon", PokemonType.PSYCHIC, null, 1.7, 60.8, AbilityId.PRESSURE, AbilityId.NONE, AbilityId.NONE, 600, 50, 150, 50, 150, 50, 150, 3, 0, 300, GrowthRate.SLOW, null, false, true, new PokemonSpecies(SpeciesId.DEOXYS, 3, false, false, true, "DNA Pokémon", PokemonType.PSYCHIC, null, 1.7, 60.8, AbilityId.PRESSURE, AbilityId.NONE, AbilityId.NONE, 600, 50, 150, 50, 150, 50, 150, 3, 0, 300, GrowthRate.SLOW, null, false, true,
@ -2274,10 +2270,10 @@ export function initSpecies() {
new PokemonSpecies(SpeciesId.WHIMSICOTT, 5, false, false, false, "Windveiled Pokémon", PokemonType.GRASS, PokemonType.FAIRY, 0.7, 6.6, AbilityId.PRANKSTER, AbilityId.INFILTRATOR, AbilityId.CHLOROPHYLL, 480, 60, 67, 85, 77, 75, 116, 75, 50, 168, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(SpeciesId.WHIMSICOTT, 5, false, false, false, "Windveiled Pokémon", PokemonType.GRASS, PokemonType.FAIRY, 0.7, 6.6, AbilityId.PRANKSTER, AbilityId.INFILTRATOR, AbilityId.CHLOROPHYLL, 480, 60, 67, 85, 77, 75, 116, 75, 50, 168, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(SpeciesId.PETILIL, 5, false, false, false, "Bulb Pokémon", PokemonType.GRASS, null, 0.5, 6.6, AbilityId.CHLOROPHYLL, AbilityId.OWN_TEMPO, AbilityId.LEAF_GUARD, 280, 45, 35, 50, 70, 50, 30, 190, 50, 56, GrowthRate.MEDIUM_FAST, 0, false), new PokemonSpecies(SpeciesId.PETILIL, 5, false, false, false, "Bulb Pokémon", PokemonType.GRASS, null, 0.5, 6.6, AbilityId.CHLOROPHYLL, AbilityId.OWN_TEMPO, AbilityId.LEAF_GUARD, 280, 45, 35, 50, 70, 50, 30, 190, 50, 56, GrowthRate.MEDIUM_FAST, 0, false),
new PokemonSpecies(SpeciesId.LILLIGANT, 5, false, false, false, "Flowering Pokémon", PokemonType.GRASS, null, 1.1, 16.3, AbilityId.CHLOROPHYLL, AbilityId.OWN_TEMPO, AbilityId.LEAF_GUARD, 480, 70, 60, 75, 110, 75, 90, 75, 50, 168, GrowthRate.MEDIUM_FAST, 0, false), new PokemonSpecies(SpeciesId.LILLIGANT, 5, false, false, false, "Flowering Pokémon", PokemonType.GRASS, null, 1.1, 16.3, AbilityId.CHLOROPHYLL, AbilityId.OWN_TEMPO, AbilityId.LEAF_GUARD, 480, 70, 60, 75, 110, 75, 90, 75, 50, 168, GrowthRate.MEDIUM_FAST, 0, false),
new PokemonSpecies(SpeciesId.BASCULIN, 5, false, false, false, "Hostile Pokémon", PokemonType.WATER, null, 1, 18, AbilityId.RECKLESS, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 25, 50, 161, GrowthRate.MEDIUM_FAST, 50, false, false, new PokemonSpecies(SpeciesId.BASCULIN, 5, false, false, false, "Hostile Pokémon", PokemonType.WATER, null, 1, 18, AbilityId.RECKLESS, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 190, 50, 161, GrowthRate.MEDIUM_FAST, 50, false, false,
new PokemonForm("Red-Striped Form", "red-striped", PokemonType.WATER, null, 1, 18, AbilityId.RECKLESS, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 25, 50, 161, false, null, true), new PokemonForm("Red-Striped Form", "red-striped", PokemonType.WATER, null, 1, 18, AbilityId.RECKLESS, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 190, 50, 161, false, null, true),
new PokemonForm("Blue-Striped Form", "blue-striped", PokemonType.WATER, null, 1, 18, AbilityId.ROCK_HEAD, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 25, 50, 161, false, null, true), new PokemonForm("Blue-Striped Form", "blue-striped", PokemonType.WATER, null, 1, 18, AbilityId.ROCK_HEAD, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 190, 50, 161, false, null, true),
new PokemonForm("White-Striped Form", "white-striped", PokemonType.WATER, null, 1, 18, AbilityId.RATTLED, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 25, 50, 161, false, null, true), new PokemonForm("White-Striped Form", "white-striped", PokemonType.WATER, null, 1, 18, AbilityId.RATTLED, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 460, 70, 92, 65, 80, 55, 98, 190, 50, 161, false, null, true),
), ),
new PokemonSpecies(SpeciesId.SANDILE, 5, false, false, false, "Desert Croc Pokémon", PokemonType.GROUND, PokemonType.DARK, 0.7, 15.2, AbilityId.INTIMIDATE, AbilityId.MOXIE, AbilityId.ANGER_POINT, 292, 50, 72, 35, 35, 35, 65, 180, 50, 58, GrowthRate.MEDIUM_SLOW, 50, false), new PokemonSpecies(SpeciesId.SANDILE, 5, false, false, false, "Desert Croc Pokémon", PokemonType.GROUND, PokemonType.DARK, 0.7, 15.2, AbilityId.INTIMIDATE, AbilityId.MOXIE, AbilityId.ANGER_POINT, 292, 50, 72, 35, 35, 35, 65, 180, 50, 58, GrowthRate.MEDIUM_SLOW, 50, false),
new PokemonSpecies(SpeciesId.KROKOROK, 5, false, false, false, "Desert Croc Pokémon", PokemonType.GROUND, PokemonType.DARK, 1, 33.4, AbilityId.INTIMIDATE, AbilityId.MOXIE, AbilityId.ANGER_POINT, 351, 60, 82, 45, 45, 45, 74, 90, 50, 123, GrowthRate.MEDIUM_SLOW, 50, false), new PokemonSpecies(SpeciesId.KROKOROK, 5, false, false, false, "Desert Croc Pokémon", PokemonType.GROUND, PokemonType.DARK, 1, 33.4, AbilityId.INTIMIDATE, AbilityId.MOXIE, AbilityId.ANGER_POINT, 351, 60, 82, 45, 45, 45, 74, 90, 50, 123, GrowthRate.MEDIUM_SLOW, 50, false),
@ -2744,10 +2740,10 @@ export function initSpecies() {
new PokemonSpecies(SpeciesId.TAPU_LELE, 7, true, false, false, "Land Spirit Pokémon", PokemonType.PSYCHIC, PokemonType.FAIRY, 1.2, 18.6, AbilityId.PSYCHIC_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 85, 75, 130, 115, 95, 3, 50, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.TAPU_LELE, 7, true, false, false, "Land Spirit Pokémon", PokemonType.PSYCHIC, PokemonType.FAIRY, 1.2, 18.6, AbilityId.PSYCHIC_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 85, 75, 130, 115, 95, 3, 50, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.TAPU_BULU, 7, true, false, false, "Land Spirit Pokémon", PokemonType.GRASS, PokemonType.FAIRY, 1.9, 45.5, AbilityId.GRASSY_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 130, 115, 85, 95, 75, 3, 50, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.TAPU_BULU, 7, true, false, false, "Land Spirit Pokémon", PokemonType.GRASS, PokemonType.FAIRY, 1.9, 45.5, AbilityId.GRASSY_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 130, 115, 85, 95, 75, 3, 50, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.TAPU_FINI, 7, true, false, false, "Land Spirit Pokémon", PokemonType.WATER, PokemonType.FAIRY, 1.3, 21.2, AbilityId.MISTY_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 75, 115, 95, 130, 85, 3, 50, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.TAPU_FINI, 7, true, false, false, "Land Spirit Pokémon", PokemonType.WATER, PokemonType.FAIRY, 1.3, 21.2, AbilityId.MISTY_SURGE, AbilityId.NONE, AbilityId.TELEPATHY, 570, 70, 75, 115, 95, 130, 85, 3, 50, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.COSMOG, 7, true, false, false, "Nebula Pokémon", PokemonType.PSYCHIC, null, 0.2, 0.1, AbilityId.UNAWARE, AbilityId.NONE, AbilityId.NONE, 200, 43, 29, 31, 29, 31, 37, 45, 0, 40, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.COSMOG, 7, true, false, false, "Nebula Pokémon", PokemonType.PSYCHIC, null, 0.2, 0.1, AbilityId.UNAWARE, AbilityId.NONE, AbilityId.NONE, 200, 43, 29, 31, 29, 31, 37, 3, 0, 40, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.COSMOEM, 7, true, false, false, "Protostar Pokémon", PokemonType.PSYCHIC, null, 0.1, 999.9, AbilityId.STURDY, AbilityId.NONE, AbilityId.NONE, 400, 43, 29, 131, 29, 131, 37, 45, 0, 140, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.COSMOEM, 7, true, false, false, "Protostar Pokémon", PokemonType.PSYCHIC, null, 0.1, 999.9, AbilityId.STURDY, AbilityId.NONE, AbilityId.NONE, 400, 43, 29, 131, 29, 131, 37, 3, 0, 140, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.SOLGALEO, 7, false, true, false, "Sunne Pokémon", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, AbilityId.FULL_METAL_BODY, AbilityId.NONE, AbilityId.NONE, 680, 137, 137, 107, 113, 89, 97, 45, 0, 340, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.SOLGALEO, 7, false, true, false, "Sunne Pokémon", PokemonType.PSYCHIC, PokemonType.STEEL, 3.4, 230, AbilityId.FULL_METAL_BODY, AbilityId.NONE, AbilityId.NONE, 680, 137, 137, 107, 113, 89, 97, 3, 0, 340, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.LUNALA, 7, false, true, false, "Moone Pokémon", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, AbilityId.SHADOW_SHIELD, AbilityId.NONE, AbilityId.NONE, 680, 137, 113, 89, 137, 107, 97, 45, 0, 340, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.LUNALA, 7, false, true, false, "Moone Pokémon", PokemonType.PSYCHIC, PokemonType.GHOST, 4, 120, AbilityId.SHADOW_SHIELD, AbilityId.NONE, AbilityId.NONE, 680, 137, 113, 89, 137, 107, 97, 3, 0, 340, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.NIHILEGO, 7, true, false, false, "Parasite Pokémon", PokemonType.ROCK, PokemonType.POISON, 1.2, 55.5, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 109, 53, 47, 127, 131, 103, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.NIHILEGO, 7, true, false, false, "Parasite Pokémon", PokemonType.ROCK, PokemonType.POISON, 1.2, 55.5, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 109, 53, 47, 127, 131, 103, 45, 0, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.BUZZWOLE, 7, true, false, false, "Swollen Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 2.4, 333.6, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 107, 139, 139, 53, 53, 79, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.BUZZWOLE, 7, true, false, false, "Swollen Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 2.4, 333.6, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 107, 139, 139, 53, 53, 79, 45, 0, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.PHEROMOSA, 7, true, false, false, "Lissome Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 1.8, 25, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 71, 137, 37, 137, 37, 151, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.PHEROMOSA, 7, true, false, false, "Lissome Pokémon", PokemonType.BUG, PokemonType.FIGHTING, 1.8, 25, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 71, 137, 37, 137, 37, 151, 45, 0, 285, GrowthRate.SLOW, null, false),
@ -2755,11 +2751,11 @@ export function initSpecies() {
new PokemonSpecies(SpeciesId.CELESTEELA, 7, true, false, false, "Launch Pokémon", PokemonType.STEEL, PokemonType.FLYING, 9.2, 999.9, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 97, 101, 103, 107, 101, 61, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.CELESTEELA, 7, true, false, false, "Launch Pokémon", PokemonType.STEEL, PokemonType.FLYING, 9.2, 999.9, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 97, 101, 103, 107, 101, 61, 45, 0, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.KARTANA, 7, true, false, false, "Drawn Sword Pokémon", PokemonType.GRASS, PokemonType.STEEL, 0.3, 0.1, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 59, 181, 131, 59, 31, 109, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.KARTANA, 7, true, false, false, "Drawn Sword Pokémon", PokemonType.GRASS, PokemonType.STEEL, 0.3, 0.1, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 59, 181, 131, 59, 31, 109, 45, 0, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.GUZZLORD, 7, true, false, false, "Junkivore Pokémon", PokemonType.DARK, PokemonType.DRAGON, 5.5, 888, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 223, 101, 53, 97, 53, 43, 45, 0, 285, GrowthRate.SLOW, null, false), new PokemonSpecies(SpeciesId.GUZZLORD, 7, true, false, false, "Junkivore Pokémon", PokemonType.DARK, PokemonType.DRAGON, 5.5, 888, AbilityId.BEAST_BOOST, AbilityId.NONE, AbilityId.NONE, 570, 223, 101, 53, 97, 53, 43, 45, 0, 285, GrowthRate.SLOW, null, false),
new PokemonSpecies(SpeciesId.NECROZMA, 7, false, true, false, "Prism Pokémon", PokemonType.PSYCHIC, null, 2.4, 230, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 600, 97, 107, 101, 127, 89, 79, 255, 0, 300, GrowthRate.SLOW, null, false, false, new PokemonSpecies(SpeciesId.NECROZMA, 7, false, true, false, "Prism Pokémon", PokemonType.PSYCHIC, null, 2.4, 230, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 600, 97, 107, 101, 127, 89, 79, 3, 0, 300, GrowthRate.SLOW, null, false, false,
new PokemonForm("Normal", "", PokemonType.PSYCHIC, null, 2.4, 230, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 600, 97, 107, 101, 127, 89, 79, 255, 0, 300, false, null, true), new PokemonForm("Normal", "", PokemonType.PSYCHIC, null, 2.4, 230, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 600, 97, 107, 101, 127, 89, 79, 3, 0, 300, false, null, true),
new PokemonForm("Dusk Mane", "dusk-mane", PokemonType.PSYCHIC, PokemonType.STEEL, 3.8, 460, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 680, 97, 157, 127, 113, 109, 77, 255, 0, 340), new PokemonForm("Dusk Mane", "dusk-mane", PokemonType.PSYCHIC, PokemonType.STEEL, 3.8, 460, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 680, 97, 157, 127, 113, 109, 77, 3, 0, 340),
new PokemonForm("Dawn Wings", "dawn-wings", PokemonType.PSYCHIC, PokemonType.GHOST, 4.2, 350, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 680, 97, 113, 109, 157, 127, 77, 255, 0, 340), new PokemonForm("Dawn Wings", "dawn-wings", PokemonType.PSYCHIC, PokemonType.GHOST, 4.2, 350, AbilityId.PRISM_ARMOR, AbilityId.NONE, AbilityId.NONE, 680, 97, 113, 109, 157, 127, 77, 3, 0, 340),
new PokemonForm("Ultra", "ultra", PokemonType.PSYCHIC, PokemonType.DRAGON, 7.5, 230, AbilityId.NEUROFORCE, AbilityId.NONE, AbilityId.NONE, 754, 97, 167, 97, 167, 97, 129, 255, 0, 377), new PokemonForm("Ultra", "ultra", PokemonType.PSYCHIC, PokemonType.DRAGON, 7.5, 230, AbilityId.NEUROFORCE, AbilityId.NONE, AbilityId.NONE, 754, 97, 167, 97, 167, 97, 129, 3, 0, 377),
), ),
new PokemonSpecies(SpeciesId.MAGEARNA, 7, false, false, true, "Artificial Pokémon", PokemonType.STEEL, PokemonType.FAIRY, 1, 80.5, AbilityId.SOUL_HEART, AbilityId.NONE, AbilityId.NONE, 600, 80, 95, 115, 130, 115, 65, 3, 0, 300, GrowthRate.SLOW, null, false, false, new PokemonSpecies(SpeciesId.MAGEARNA, 7, false, false, true, "Artificial Pokémon", PokemonType.STEEL, PokemonType.FAIRY, 1, 80.5, AbilityId.SOUL_HEART, AbilityId.NONE, AbilityId.NONE, 600, 80, 95, 115, 130, 115, 65, 3, 0, 300, GrowthRate.SLOW, null, false, false,
new PokemonForm("Normal", "", PokemonType.STEEL, PokemonType.FAIRY, 1, 80.5, AbilityId.SOUL_HEART, AbilityId.NONE, AbilityId.NONE, 600, 80, 95, 115, 130, 115, 65, 3, 0, 300, false, null, true), new PokemonForm("Normal", "", PokemonType.STEEL, PokemonType.FAIRY, 1, 80.5, AbilityId.SOUL_HEART, AbilityId.NONE, AbilityId.NONE, 600, 80, 95, 115, 130, 115, 65, 3, 0, 300, false, null, true),
@ -2968,15 +2964,15 @@ export function initSpecies() {
new PokemonForm("Ice", "ice", PokemonType.PSYCHIC, PokemonType.ICE, 2.4, 809.1, AbilityId.AS_ONE_GLASTRIER, AbilityId.NONE, AbilityId.NONE, 680, 100, 165, 150, 85, 130, 50, 3, 100, 340), new PokemonForm("Ice", "ice", PokemonType.PSYCHIC, PokemonType.ICE, 2.4, 809.1, AbilityId.AS_ONE_GLASTRIER, AbilityId.NONE, AbilityId.NONE, 680, 100, 165, 150, 85, 130, 50, 3, 100, 340),
new PokemonForm("Shadow", "shadow", PokemonType.PSYCHIC, PokemonType.GHOST, 2.4, 53.6, AbilityId.AS_ONE_SPECTRIER, AbilityId.NONE, AbilityId.NONE, 680, 100, 85, 80, 165, 100, 150, 3, 100, 340), new PokemonForm("Shadow", "shadow", PokemonType.PSYCHIC, PokemonType.GHOST, 2.4, 53.6, AbilityId.AS_ONE_SPECTRIER, AbilityId.NONE, AbilityId.NONE, 680, 100, 85, 80, 165, 100, 150, 3, 100, 340),
), ),
new PokemonSpecies(SpeciesId.WYRDEER, 8, false, false, false, "Big Horn Pokémon", PokemonType.NORMAL, PokemonType.PSYCHIC, 1.8, 95.1, AbilityId.INTIMIDATE, AbilityId.FRISK, AbilityId.SAP_SIPPER, 525, 103, 105, 72, 105, 75, 65, 135, 50, 263, GrowthRate.SLOW, 50, false), new PokemonSpecies(SpeciesId.WYRDEER, 8, false, false, false, "Big Horn Pokémon", PokemonType.NORMAL, PokemonType.PSYCHIC, 1.8, 95.1, AbilityId.INTIMIDATE, AbilityId.FRISK, AbilityId.SAP_SIPPER, 525, 103, 105, 72, 105, 75, 65, 45, 50, 263, GrowthRate.SLOW, 50, false),
new PokemonSpecies(SpeciesId.KLEAVOR, 8, false, false, false, "Axe Pokémon", PokemonType.BUG, PokemonType.ROCK, 1.8, 89, AbilityId.SWARM, AbilityId.SHEER_FORCE, AbilityId.SHARPNESS, 500, 70, 135, 95, 45, 70, 85, 115, 50, 175, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(SpeciesId.KLEAVOR, 8, false, false, false, "Axe Pokémon", PokemonType.BUG, PokemonType.ROCK, 1.8, 89, AbilityId.SWARM, AbilityId.SHEER_FORCE, AbilityId.SHARPNESS, 500, 70, 135, 95, 45, 70, 85, 15, 50, 175, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(SpeciesId.URSALUNA, 8, false, false, false, "Peat Pokémon", PokemonType.GROUND, PokemonType.NORMAL, 2.4, 290, AbilityId.GUTS, AbilityId.BULLETPROOF, AbilityId.UNNERVE, 550, 130, 140, 105, 45, 80, 50, 75, 50, 275, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(SpeciesId.URSALUNA, 8, false, false, false, "Peat Pokémon", PokemonType.GROUND, PokemonType.NORMAL, 2.4, 290, AbilityId.GUTS, AbilityId.BULLETPROOF, AbilityId.UNNERVE, 550, 130, 140, 105, 45, 80, 50, 20, 50, 275, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(SpeciesId.BASCULEGION, 8, false, false, false, "Big Fish Pokémon", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 112, 65, 80, 75, 78, 135, 50, 265, GrowthRate.MEDIUM_FAST, 50, false, false, new PokemonSpecies(SpeciesId.BASCULEGION, 8, false, false, false, "Big Fish Pokémon", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 112, 65, 80, 75, 78, 45, 50, 265, GrowthRate.MEDIUM_FAST, 50, false, false,
new PokemonForm("Male", "male", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 112, 65, 80, 75, 78, 135, 50, 265, false, "", true), new PokemonForm("Male", "male", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 112, 65, 80, 75, 78, 45, 50, 265, false, "", true),
new PokemonForm("Female", "female", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 92, 65, 100, 75, 78, 135, 50, 265, false, null, true), new PokemonForm("Female", "female", PokemonType.WATER, PokemonType.GHOST, 3, 110, AbilityId.SWIFT_SWIM, AbilityId.ADAPTABILITY, AbilityId.MOLD_BREAKER, 530, 120, 92, 65, 100, 75, 78, 45, 50, 265, false, null, true),
), ),
new PokemonSpecies(SpeciesId.SNEASLER, 8, false, false, false, "Free Climb Pokémon", PokemonType.FIGHTING, PokemonType.POISON, 1.3, 43, AbilityId.PRESSURE, AbilityId.UNBURDEN, AbilityId.POISON_TOUCH, 510, 80, 130, 60, 40, 80, 120, 135, 50, 102, GrowthRate.MEDIUM_SLOW, 50, false), new PokemonSpecies(SpeciesId.SNEASLER, 8, false, false, false, "Free Climb Pokémon", PokemonType.FIGHTING, PokemonType.POISON, 1.3, 43, AbilityId.PRESSURE, AbilityId.UNBURDEN, AbilityId.POISON_TOUCH, 510, 80, 130, 60, 40, 80, 120, 20, 50, 102, GrowthRate.MEDIUM_SLOW, 50, false),
new PokemonSpecies(SpeciesId.OVERQWIL, 8, false, false, false, "Pin Cluster Pokémon", PokemonType.DARK, PokemonType.POISON, 2.5, 60.5, AbilityId.POISON_POINT, AbilityId.SWIFT_SWIM, AbilityId.INTIMIDATE, 510, 85, 115, 95, 65, 65, 85, 135, 50, 179, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(SpeciesId.OVERQWIL, 8, false, false, false, "Pin Cluster Pokémon", PokemonType.DARK, PokemonType.POISON, 2.5, 60.5, AbilityId.POISON_POINT, AbilityId.SWIFT_SWIM, AbilityId.INTIMIDATE, 510, 85, 115, 95, 65, 65, 85, 45, 50, 179, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(SpeciesId.ENAMORUS, 8, true, false, false, "Love-Hate Pokémon", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.CUTE_CHARM, AbilityId.NONE, AbilityId.CONTRARY, 580, 74, 115, 70, 135, 80, 106, 3, 50, 116, GrowthRate.SLOW, 0, false, true, new PokemonSpecies(SpeciesId.ENAMORUS, 8, true, false, false, "Love-Hate Pokémon", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.CUTE_CHARM, AbilityId.NONE, AbilityId.CONTRARY, 580, 74, 115, 70, 135, 80, 106, 3, 50, 116, GrowthRate.SLOW, 0, false, true,
new PokemonForm("Incarnate Forme", "incarnate", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.CUTE_CHARM, AbilityId.NONE, AbilityId.CONTRARY, 580, 74, 115, 70, 135, 80, 106, 3, 50, 116, false, null, true), new PokemonForm("Incarnate Forme", "incarnate", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.CUTE_CHARM, AbilityId.NONE, AbilityId.CONTRARY, 580, 74, 115, 70, 135, 80, 106, 3, 50, 116, false, null, true),
new PokemonForm("Therian Forme", "therian", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.OVERCOAT, AbilityId.NONE, AbilityId.OVERCOAT, 580, 74, 115, 110, 135, 100, 46, 3, 50, 116), new PokemonForm("Therian Forme", "therian", PokemonType.FAIRY, PokemonType.FLYING, 1.6, 48, AbilityId.OVERCOAT, AbilityId.NONE, AbilityId.OVERCOAT, 580, 74, 115, 110, 135, 100, 46, 3, 50, 116),

View File

@ -1,4 +1,4 @@
import type { TrainerTierPools } from "#app/data/trainers/typedefs"; import type { TrainerTierPools } from "#app/@types/trainer-funcs";
import { TrainerPoolTier } from "#enums/trainer-pool-tier"; import { TrainerPoolTier } from "#enums/trainer-pool-tier";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";

View File

@ -48,7 +48,7 @@ import type {
TrainerTierPools, TrainerTierPools,
TrainerConfigs, TrainerConfigs,
PartyMemberFuncs, PartyMemberFuncs,
} from "./typedefs"; } from "../../@types/trainer-funcs";
/** Minimum BST for Pokemon generated onto the Elite Four's teams */ /** Minimum BST for Pokemon generated onto the Elite Four's teams */
const ELITE_FOUR_MINIMUM_BST = 460; const ELITE_FOUR_MINIMUM_BST = 460;

View File

@ -1,17 +0,0 @@
export function getData() {
const dataStr = localStorage.getItem("data");
if (!dataStr) {
return null;
}
return JSON.parse(atob(dataStr), (k, v) =>
k.endsWith("Attr") && !["natureAttr", "abilityAttr", "passiveAttr"].includes(k) ? BigInt(v) : v,
);
}
export function getSession() {
const sessionStr = localStorage.getItem("sessionData");
if (!sessionStr) {
return null;
}
return JSON.parse(atob(sessionStr));
}

View File

@ -232,7 +232,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import { FaintPhase } from "#app/phases/faint-phase"; import { FaintPhase } from "#app/phases/faint-phase";
import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase"; import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
@ -504,7 +503,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (level > 1) { if (level > 1) {
const fused = new BooleanHolder(globalScene.gameMode.isSplicedOnly); const fused = new BooleanHolder(globalScene.gameMode.isSplicedOnly);
if (!fused.value && !this.isPlayer() && !this.hasTrainer()) { if (!fused.value && this.isEnemy() && !this.hasTrainer()) {
globalScene.applyModifier(EnemyFusionChanceModifier, false, fused); globalScene.applyModifier(EnemyFusionChanceModifier, false, fused);
} }
@ -789,7 +788,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return true; return true;
} }
abstract isPlayer(): boolean; abstract isPlayer(): this is PlayerPokemon;
abstract isEnemy(): this is EnemyPokemon;
abstract hasTrainer(): boolean; abstract hasTrainer(): boolean;
@ -1293,19 +1294,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
*/ */
isOffsetBySubstitute(): boolean { isOffsetBySubstitute(): boolean {
const substitute = this.getTag(SubstituteTag); const substitute = this.getTag(SubstituteTag);
if (substitute) { if (!substitute || substitute.sprite === undefined) {
if (substitute.sprite === undefined) { return false;
return false;
}
// During the Pokemon's MoveEffect phase, the offset is removed to put the Pokemon "in focus"
const currentPhase = globalScene.getCurrentPhase();
if (currentPhase instanceof MoveEffectPhase && currentPhase.getPokemon() === this) {
return false;
}
return true;
} }
return false; // During the Pokemon's MoveEffect phase, the offset is removed to put the Pokemon "in focus"
const currentPhase = globalScene.getCurrentPhase();
return !(currentPhase?.is("MoveEffectPhase") && currentPhase.getPokemon() === this);
} }
/** If this Pokemon has a Substitute on the field, removes its sprite from the field. */ /** If this Pokemon has a Substitute on the field, removes its sprite from the field. */
@ -2058,7 +2052,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (Overrides.ABILITY_OVERRIDE && this.isPlayer()) { if (Overrides.ABILITY_OVERRIDE && this.isPlayer()) {
return allAbilities[Overrides.ABILITY_OVERRIDE]; return allAbilities[Overrides.ABILITY_OVERRIDE];
} }
if (Overrides.OPP_ABILITY_OVERRIDE && !this.isPlayer()) { if (Overrides.OPP_ABILITY_OVERRIDE && this.isEnemy()) {
return allAbilities[Overrides.OPP_ABILITY_OVERRIDE]; return allAbilities[Overrides.OPP_ABILITY_OVERRIDE];
} }
if (this.isFusion()) { if (this.isFusion()) {
@ -2088,7 +2082,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (Overrides.PASSIVE_ABILITY_OVERRIDE && this.isPlayer()) { if (Overrides.PASSIVE_ABILITY_OVERRIDE && this.isPlayer()) {
return allAbilities[Overrides.PASSIVE_ABILITY_OVERRIDE]; return allAbilities[Overrides.PASSIVE_ABILITY_OVERRIDE];
} }
if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && !this.isPlayer()) { if (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE && this.isEnemy()) {
return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE]; return allAbilities[Overrides.OPP_PASSIVE_ABILITY_OVERRIDE];
} }
if (!isNullOrUndefined(this.customPokemonData.passive) && this.customPokemonData.passive !== -1) { if (!isNullOrUndefined(this.customPokemonData.passive) && this.customPokemonData.passive !== -1) {
@ -2160,7 +2154,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// returns override if valid for current case // returns override if valid for current case
if ( if (
(Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer()) || (Overrides.HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isPlayer()) ||
(Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE === false && !this.isPlayer()) (Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE === false && this.isEnemy())
) { ) {
return false; return false;
} }
@ -2168,7 +2162,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE) && ((Overrides.PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.HAS_PASSIVE_ABILITY_OVERRIDE) &&
this.isPlayer()) || this.isPlayer()) ||
((Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE) && ((Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== AbilityId.NONE || Overrides.OPP_HAS_PASSIVE_ABILITY_OVERRIDE) &&
!this.isPlayer()) this.isEnemy())
) { ) {
return true; return true;
} }
@ -2177,7 +2171,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const { currentBattle, gameMode } = globalScene; const { currentBattle, gameMode } = globalScene;
const waveIndex = currentBattle?.waveIndex; const waveIndex = currentBattle?.waveIndex;
if ( if (
this instanceof EnemyPokemon && this.isEnemy() &&
(currentBattle?.battleSpec === BattleSpec.FINAL_BOSS || (currentBattle?.battleSpec === BattleSpec.FINAL_BOSS ||
gameMode.isEndlessMinorBoss(waveIndex) || gameMode.isEndlessMinorBoss(waveIndex) ||
gameMode.isEndlessMajorBoss(waveIndex)) gameMode.isEndlessMajorBoss(waveIndex))
@ -2242,10 +2236,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.getAbility(ignoreOverride).id === ability && (!canApply || this.canApplyAbility())) { if (this.getAbility(ignoreOverride).id === ability && (!canApply || this.canApplyAbility())) {
return true; return true;
} }
if (this.getPassiveAbility().id === ability && this.hasPassive() && (!canApply || this.canApplyAbility(true))) { return this.getPassiveAbility().id === ability && this.hasPassive() && (!canApply || this.canApplyAbility(true));
return true;
}
return false;
} }
/** /**
@ -2262,10 +2253,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).hasAttr(attrType)) { if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).hasAttr(attrType)) {
return true; return true;
} }
if (this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().hasAttr(attrType)) { return this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().hasAttr(attrType);
return true;
}
return false;
} }
/** /**
@ -2993,9 +2981,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
let fusionOverride: PokemonSpecies | undefined = undefined; let fusionOverride: PokemonSpecies | undefined = undefined;
if (forStarter && this instanceof PlayerPokemon && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) { if (forStarter && this.isPlayer() && Overrides.STARTER_FUSION_SPECIES_OVERRIDE) {
fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE); fusionOverride = getPokemonSpecies(Overrides.STARTER_FUSION_SPECIES_OVERRIDE);
} else if (this instanceof EnemyPokemon && Overrides.OPP_FUSION_SPECIES_OVERRIDE) { } else if (this.isEnemy() && Overrides.OPP_FUSION_SPECIES_OVERRIDE) {
fusionOverride = getPokemonSpecies(Overrides.OPP_FUSION_SPECIES_OVERRIDE); fusionOverride = getPokemonSpecies(Overrides.OPP_FUSION_SPECIES_OVERRIDE);
} }
@ -3306,7 +3294,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.battleInfo.setX(this.battleInfo.x + (this.isPlayer() ? 150 : !this.isBoss() ? -150 : -198)); this.battleInfo.setX(this.battleInfo.x + (this.isPlayer() ? 150 : !this.isBoss() ? -150 : -198));
this.battleInfo.setVisible(true); this.battleInfo.setVisible(true);
if (this.isPlayer()) { if (this.isPlayer()) {
this.battleInfo.expMaskRect.x += 150; // TODO: How do you get this to not require a private property access?
this["battleInfo"].expMaskRect.x += 150;
} }
globalScene.tweens.add({ globalScene.tweens.add({
targets: [this.battleInfo, this.battleInfo.expMaskRect], targets: [this.battleInfo, this.battleInfo.expMaskRect],
@ -3327,7 +3316,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
ease: "Cubic.easeIn", ease: "Cubic.easeIn",
onComplete: () => { onComplete: () => {
if (this.isPlayer()) { if (this.isPlayer()) {
this.battleInfo.expMaskRect.x -= 150; // TODO: How do you get this to not require a private property access?
this["battleInfo"].expMaskRect.x -= 150;
} }
this.battleInfo.setVisible(false); this.battleInfo.setVisible(false);
this.battleInfo.setX(this.battleInfo.x - (this.isPlayer() ? 150 : !this.isBoss() ? -150 : -198)); this.battleInfo.setX(this.battleInfo.x - (this.isPlayer() ? 150 : !this.isBoss() ? -150 : -198));
@ -3422,7 +3412,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @returns An array of Pokémon on the allied field. * @returns An array of Pokémon on the allied field.
*/ */
getAlliedField(): Pokemon[] { getAlliedField(): Pokemon[] {
return this instanceof PlayerPokemon ? globalScene.getPlayerField() : globalScene.getEnemyField(); return this.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
} }
/** /**
@ -4274,7 +4264,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Copy all stat stages // Copy all stat stages
for (const s of BATTLE_STATS) { for (const s of BATTLE_STATS) {
const sourceStage = source.getStatStage(s); const sourceStage = source.getStatStage(s);
if (this instanceof PlayerPokemon && sourceStage === 6) { if (this.isPlayer() && sourceStage === 6) {
globalScene.validateAchv(achvs.TRANSFER_MAX_STAT_STAGE); globalScene.validateAchv(achvs.TRANSFER_MAX_STAT_STAGE);
} }
this.setStatStage(s, sourceStage); this.setStatStage(s, sourceStage);
@ -4775,7 +4765,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
*/ */
if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) { if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) {
const currentPhase = globalScene.getCurrentPhase(); const currentPhase = globalScene.getCurrentPhase();
if (currentPhase instanceof MoveEffectPhase && currentPhase.getUserPokemon() === this) { if (currentPhase?.is("MoveEffectPhase") && currentPhase.getUserPokemon() === this) {
this.turnData.hitCount = 1; this.turnData.hitCount = 1;
this.turnData.hitsLeft = 1; this.turnData.hitsLeft = 1;
} }
@ -5465,10 +5455,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if ((ownedAbilityAttrs & 2) > 0 && this.hasSameAbilityInRootForm(1)) { if ((ownedAbilityAttrs & 2) > 0 && this.hasSameAbilityInRootForm(1)) {
return true; return true;
} }
if ((ownedAbilityAttrs & 4) > 0 && this.hasSameAbilityInRootForm(2)) { return (ownedAbilityAttrs & 4) > 0 && this.hasSameAbilityInRootForm(2);
return true;
}
return false;
} }
/** /**
@ -5485,7 +5472,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
heldItem.stackCount--; heldItem.stackCount--;
if (heldItem.stackCount <= 0) { if (heldItem.stackCount <= 0) {
globalScene.removeModifier(heldItem, !this.isPlayer()); globalScene.removeModifier(heldItem, this.isEnemy());
} }
if (forBattle) { if (forBattle) {
applyPostItemLostAbAttrs(PostItemLostAbAttr, this, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, this, false);
@ -5558,15 +5545,19 @@ export class PlayerPokemon extends Pokemon {
this.battleInfo.initInfo(this); this.battleInfo.initInfo(this);
} }
isPlayer(): boolean { override isPlayer(): this is PlayerPokemon {
return true; return true;
} }
hasTrainer(): boolean { override isEnemy(): this is EnemyPokemon {
return false;
}
override hasTrainer(): boolean {
return true; return true;
} }
isBoss(): boolean { override isBoss(): boolean {
return false; return false;
} }
@ -6511,15 +6502,19 @@ export class EnemyPokemon extends Pokemon {
return [sortedBenefitScores[targetIndex][0]]; return [sortedBenefitScores[targetIndex][0]];
} }
isPlayer() { override isPlayer(): this is PlayerPokemon {
return false; return false;
} }
hasTrainer(): boolean { override isEnemy(): this is EnemyPokemon {
return true;
}
override hasTrainer(): boolean {
return !!this.trainerSlot; return !!this.trainerSlot;
} }
isBoss(): boolean { override isBoss(): boolean {
return !!this.bossSegments; return !!this.bossSegments;
} }

View File

@ -1,4 +1,3 @@
export const starterColors: StarterColors = {}; export const starterColors: {
interface StarterColors {
[key: string]: [string, string]; [key: string]: [string, string];
} } = {};

View File

@ -16,7 +16,7 @@ export function getPokemonNameWithAffix(pokemon: Pokemon | undefined, useIllusio
switch (globalScene.currentBattle.battleSpec) { switch (globalScene.currentBattle.battleSpec) {
case BattleSpec.DEFAULT: case BattleSpec.DEFAULT:
return !pokemon.isPlayer() return pokemon.isEnemy()
? pokemon.hasTrainer() ? pokemon.hasTrainer()
? i18next.t("battle:foePokemonWithAffix", { ? i18next.t("battle:foePokemonWithAffix", {
pokemonName: pokemon.getNameToRender(useIllusion), pokemonName: pokemon.getNameToRender(useIllusion),
@ -26,7 +26,7 @@ export function getPokemonNameWithAffix(pokemon: Pokemon | undefined, useIllusio
}) })
: pokemon.getNameToRender(useIllusion); : pokemon.getNameToRender(useIllusion);
case BattleSpec.FINAL_BOSS: case BattleSpec.FINAL_BOSS:
return !pokemon.isPlayer() return pokemon.isEnemy()
? i18next.t("battle:foePokemonWithAffix", { pokemonName: pokemon.getNameToRender(useIllusion) }) ? i18next.t("battle:foePokemonWithAffix", { pokemonName: pokemon.getNameToRender(useIllusion) })
: pokemon.getNameToRender(useIllusion); : pokemon.getNameToRender(useIllusion);
default: default:

View File

@ -40,7 +40,6 @@ import {
type TerastallizeModifierType, type TerastallizeModifierType,
type TmModifierType, type TmModifierType,
getModifierType, getModifierType,
ModifierPoolType,
ModifierTypeGenerator, ModifierTypeGenerator,
modifierTypes, modifierTypes,
PokemonHeldItemModifierType, PokemonHeldItemModifierType,
@ -1091,10 +1090,6 @@ export class PokemonIncrementingStatModifier extends PokemonHeldItemModifier {
return new PokemonIncrementingStatModifier(this.type, this.pokemonId, this.stackCount); return new PokemonIncrementingStatModifier(this.type, this.pokemonId, this.stackCount);
} }
getArgs(): any[] {
return super.getArgs();
}
/** /**
* Checks if the {@linkcode PokemonIncrementingStatModifier} should be applied to the {@linkcode Pokemon}. * Checks if the {@linkcode PokemonIncrementingStatModifier} should be applied to the {@linkcode Pokemon}.
* @param pokemon The {@linkcode Pokemon} that holds the item * @param pokemon The {@linkcode Pokemon} that holds the item
@ -1217,10 +1212,6 @@ export class StatBoosterModifier extends PokemonHeldItemModifier {
* @see {@linkcode apply} * @see {@linkcode apply}
*/ */
export class EvolutionStatBoosterModifier extends StatBoosterModifier { export class EvolutionStatBoosterModifier extends StatBoosterModifier {
clone() {
return super.clone() as EvolutionStatBoosterModifier;
}
matchType(modifier: Modifier): boolean { matchType(modifier: Modifier): boolean {
return modifier instanceof EvolutionStatBoosterModifier; return modifier instanceof EvolutionStatBoosterModifier;
} }
@ -3232,8 +3223,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
} }
/** /**
* Steals an item from a set of target Pokemon. * Steals an item, chosen randomly, from a set of target Pokemon.
* This prioritizes high-tier held items when selecting the item to steal.
* @param pokemon The {@linkcode Pokemon} holding this item * @param pokemon The {@linkcode Pokemon} holding this item
* @param target The {@linkcode Pokemon} to steal from (optional) * @param target The {@linkcode Pokemon} to steal from (optional)
* @param _args N/A * @param _args N/A
@ -3253,30 +3243,15 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
return false; return false;
} }
const poolType = pokemon.isPlayer()
? ModifierPoolType.PLAYER
: pokemon.hasTrainer()
? ModifierPoolType.TRAINER
: ModifierPoolType.WILD;
const transferredModifierTypes: ModifierType[] = []; const transferredModifierTypes: ModifierType[] = [];
const itemModifiers = globalScene.findModifiers( const itemModifiers = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === targetPokemon.id && m.isTransferable, m => m instanceof PokemonHeldItemModifier && m.pokemonId === targetPokemon.id && m.isTransferable,
targetPokemon.isPlayer(), targetPokemon.isPlayer(),
) as PokemonHeldItemModifier[]; ) as PokemonHeldItemModifier[];
let highestItemTier = itemModifiers
.map(m => m.type.getOrInferTier(poolType))
.reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is this bang correct?
let tierItemModifiers = itemModifiers.filter(m => m.type.getOrInferTier(poolType) === highestItemTier);
for (let i = 0; i < transferredItemCount; i++) { for (let i = 0; i < transferredItemCount; i++) {
if (!tierItemModifiers.length) { if (!itemModifiers.length) {
while (highestItemTier-- && !tierItemModifiers.length) { break;
tierItemModifiers = itemModifiers.filter(m => m.type.tier === highestItemTier);
}
if (!tierItemModifiers.length) {
break;
}
} }
const randItemIndex = pokemon.randBattleSeedInt(itemModifiers.length); const randItemIndex = pokemon.randBattleSeedInt(itemModifiers.length);
const randItem = itemModifiers[randItemIndex]; const randItem = itemModifiers[randItemIndex];

View File

@ -1,9 +1,33 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type { PhaseMap, PhaseString } from "./@types/phase-types";
export class Phase { export abstract class Phase {
start() {} start() {}
end() { end() {
globalScene.shiftPhase(); globalScene.shiftPhase();
} }
/**
* The string name of the phase, used to identify the phase type for {@linkcode is}
*
* @privateremarks
*
* When implementing a phase, you must set the `phaseName` property to the name of the phase.
*/
public abstract readonly phaseName: PhaseString;
/**
* Check if the phase is of the given type without requiring `instanceof`.
*
* @param phase - The string name of the phase to check.
* @returns Whether this phase is of the provided type.
*
* @remarks
* This does not check for subclasses! It only checks if the phase is *exactly* the given type.
* This method exists to avoid circular import issues, as using `instanceof` would require importing each phase.
*/
is<K extends keyof PhaseMap>(phase: K): this is PhaseMap[K] {
return this.phaseName === phase;
}
} }

View File

@ -9,6 +9,7 @@ import { Phase } from "#app/phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export class AddEnemyBuffModifierPhase extends Phase { export class AddEnemyBuffModifierPhase extends Phase {
public readonly phaseName = "AddEnemyBuffModifierPhase";
start() { start() {
super.start(); super.start();

View File

@ -27,6 +27,7 @@ import { globalScene } from "#app/global-scene";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
export class AttemptCapturePhase extends PokemonPhase { export class AttemptCapturePhase extends PokemonPhase {
public readonly phaseName = "AttemptCapturePhase";
private pokeballType: PokeballType; private pokeballType: PokeballType;
private pokeball: Phaser.GameObjects.Sprite; private pokeball: Phaser.GameObjects.Sprite;
private originalY: number; private originalY: number;

View File

@ -17,6 +17,7 @@ import { globalScene } from "#app/global-scene";
import { SelectBiomePhase } from "./select-biome-phase"; import { SelectBiomePhase } from "./select-biome-phase";
export class AttemptRunPhase extends PokemonPhase { export class AttemptRunPhase extends PokemonPhase {
public readonly phaseName = "AttemptRunPhase";
/** For testing purposes: this is to force the pokemon to fail and escape */ /** For testing purposes: this is to force the pokemon to fail and escape */
public forceFailEscape = false; public forceFailEscape = false;

View File

@ -5,6 +5,7 @@ import { BattlePhase } from "./battle-phase";
import { GameOverPhase } from "./game-over-phase"; import { GameOverPhase } from "./game-over-phase";
export class BattleEndPhase extends BattlePhase { export class BattleEndPhase extends BattlePhase {
public readonly phaseName = "BattleEndPhase";
/** If true, will increment battles won */ /** If true, will increment battles won */
isVictory: boolean; isVictory: boolean;
@ -19,7 +20,7 @@ export class BattleEndPhase extends BattlePhase {
// cull any extra `BattleEnd` phases from the queue. // cull any extra `BattleEnd` phases from the queue.
globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => { globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => {
if (phase instanceof BattleEndPhase) { if (phase.is("BattleEndPhase")) {
this.isVictory ||= phase.isVictory; this.isVictory ||= phase.isVictory;
return false; return false;
} }
@ -28,7 +29,7 @@ export class BattleEndPhase extends BattlePhase {
// `phaseQueuePrepend` is private, so we have to use this inefficient loop. // `phaseQueuePrepend` is private, so we have to use this inefficient loop.
while ( while (
globalScene.tryRemoveUnshiftedPhase(phase => { globalScene.tryRemoveUnshiftedPhase(phase => {
if (phase instanceof BattleEndPhase) { if (phase.is("BattleEndPhase")) {
this.isVictory ||= phase.isVictory; this.isVictory ||= phase.isVictory;
return true; return true;
} }

View File

@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
export class BattlePhase extends Phase { export abstract class BattlePhase extends Phase {
showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void { showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void {
if (!globalScene.currentBattle.trainer) { if (!globalScene.currentBattle.trainer) {
console.warn("Enemy trainer is missing!"); console.warn("Enemy trainer is missing!");

View File

@ -20,6 +20,7 @@ import type Pokemon from "#app/field/pokemon";
* Also triggers Cud Chew's "repeat berry use" effects * Also triggers Cud Chew's "repeat berry use" effects
*/ */
export class BerryPhase extends FieldPhase { export class BerryPhase extends FieldPhase {
public readonly phaseName = "BerryPhase";
start() { start() {
super.start(); super.start();

View File

@ -4,6 +4,7 @@ import type { BattlerIndex } from "#app/battle";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export class CheckStatusEffectPhase extends Phase { export class CheckStatusEffectPhase extends Phase {
public readonly phaseName = "CheckStatusEffectPhase";
private order: BattlerIndex[]; private order: BattlerIndex[];
constructor(order: BattlerIndex[]) { constructor(order: BattlerIndex[]) {
super(); super();

View File

@ -10,6 +10,7 @@ import { SwitchPhase } from "./switch-phase";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
export class CheckSwitchPhase extends BattlePhase { export class CheckSwitchPhase extends BattlePhase {
public readonly phaseName = "CheckSwitchPhase";
protected fieldIndex: number; protected fieldIndex: number;
protected useName: boolean; protected useName: boolean;

View File

@ -25,6 +25,7 @@ import { ArenaTagSide } from "#app/data/arena-tag";
import { ArenaTagType } from "#app/enums/arena-tag-type"; import { ArenaTagType } from "#app/enums/arena-tag-type";
export class CommandPhase extends FieldPhase { export class CommandPhase extends FieldPhase {
public readonly phaseName = "CommandPhase";
protected fieldIndex: number; protected fieldIndex: number;
constructor(fieldIndex: number) { constructor(fieldIndex: number) {

View File

@ -5,6 +5,9 @@ import { CommonBattleAnim } from "#app/data/battle-anims";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
export class CommonAnimPhase extends PokemonPhase { export class CommonAnimPhase extends PokemonPhase {
// PokemonHealPhase extends CommonAnimPhase, and to make typescript happy,
// we need to allow phaseName to be a union of the two
public readonly phaseName: "CommonAnimPhase" | "PokemonHealPhase" | "WeatherEffectPhase" = "CommonAnimPhase";
private anim: CommonAnim | null; private anim: CommonAnim | null;
private targetIndex?: BattlerIndex; private targetIndex?: BattlerIndex;
private playOnEmptyField: boolean; private playOnEmptyField: boolean;

View File

@ -6,6 +6,7 @@ import { fixedInt } from "#app/utils/common";
import { PokemonPhase } from "#app/phases/pokemon-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase";
export class DamageAnimPhase extends PokemonPhase { export class DamageAnimPhase extends PokemonPhase {
public readonly phaseName = "DamageAnimPhase";
private amount: number; private amount: number;
private damageResult: DamageResult; private damageResult: DamageResult;
private critical: boolean; private critical: boolean;

View File

@ -20,6 +20,7 @@ import { doShinySparkleAnim } from "#app/field/anims";
* Class that represents egg hatching * Class that represents egg hatching
*/ */
export class EggHatchPhase extends Phase { export class EggHatchPhase extends Phase {
public readonly phaseName = "EggHatchPhase";
/** The egg that is hatching */ /** The egg that is hatching */
private egg: Egg; private egg: Egg;
/** The new EggHatchData for the egg/pokemon that hatches */ /** The new EggHatchData for the egg/pokemon that hatches */
@ -224,7 +225,7 @@ export class EggHatchPhase extends Phase {
} }
end() { end() {
if (globalScene.findPhase(p => p instanceof EggHatchPhase)) { if (globalScene.findPhase(p => p.is("EggHatchPhase"))) {
this.eggHatchHandler.clear(); this.eggHatchHandler.clear();
} else { } else {
globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true)); globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true));

View File

@ -16,6 +16,7 @@ import { EggHatchData } from "#app/data/egg-hatch-data";
* Also handles prompts for skipping animation, and calling the egg summary phase * Also handles prompts for skipping animation, and calling the egg summary phase
*/ */
export class EggLapsePhase extends Phase { export class EggLapsePhase extends Phase {
public readonly phaseName = "EggLapsePhase";
private eggHatchData: EggHatchData[] = []; private eggHatchData: EggHatchData[] = [];
private readonly minEggsToSkip: number = 2; private readonly minEggsToSkip: number = 2;

View File

@ -9,6 +9,7 @@ import type { EggHatchData } from "#app/data/egg-hatch-data";
* Phase is handled mostly by the egg-hatch-scene-handler UI * Phase is handled mostly by the egg-hatch-scene-handler UI
*/ */
export class EggSummaryPhase extends Phase { export class EggSummaryPhase extends Phase {
public readonly phaseName = "EggSummaryPhase";
private eggHatchData: EggHatchData[]; private eggHatchData: EggHatchData[];
constructor(eggHatchData: EggHatchData[]) { constructor(eggHatchData: EggHatchData[]) {

View File

@ -47,6 +47,8 @@ import { WEIGHT_INCREMENT_ON_SPAWN_MISS } from "#app/data/mystery-encounters/mys
import { getNatureName } from "#app/data/nature"; import { getNatureName } from "#app/data/nature";
export class EncounterPhase extends BattlePhase { export class EncounterPhase extends BattlePhase {
// Union type is necessary as this is subclassed, and typescript will otherwise complain
public readonly phaseName: "EncounterPhase" | "NextEncounterPhase" | "NewBiomeEncounterPhase" = "EncounterPhase";
private loaded: boolean; private loaded: boolean;
constructor(loaded = false) { constructor(loaded = false) {

View File

@ -5,6 +5,7 @@ import { addTextObject, TextStyle } from "#app/ui/text";
import i18next from "i18next"; import i18next from "i18next";
export class EndCardPhase extends Phase { export class EndCardPhase extends Phase {
public readonly phaseName = "EndCardPhase";
public endCard: Phaser.GameObjects.Image; public endCard: Phaser.GameObjects.Image;
public text: Phaser.GameObjects.Text; public text: Phaser.GameObjects.Text;
start(): void { start(): void {

View File

@ -3,6 +3,7 @@ import { Phase } from "#app/phase";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
export class EndEvolutionPhase extends Phase { export class EndEvolutionPhase extends Phase {
public readonly phaseName = "EndEvolutionPhase";
start() { start() {
super.start(); super.start();

View File

@ -15,6 +15,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
* @see {@linkcode EnemyPokemon.getNextMove} * @see {@linkcode EnemyPokemon.getNextMove}
*/ */
export class EnemyCommandPhase extends FieldPhase { export class EnemyCommandPhase extends FieldPhase {
public readonly phaseName = "EnemyCommandPhase";
protected fieldIndex: number; protected fieldIndex: number;
protected skipTurn = false; protected skipTurn = false;

View File

@ -19,6 +19,9 @@ import { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import { EVOLVE_MOVE } from "#app/data/balance/pokemon-level-moves"; import { EVOLVE_MOVE } from "#app/data/balance/pokemon-level-moves";
export class EvolutionPhase extends Phase { export class EvolutionPhase extends Phase {
// FormChangePhase inherits from this, but EvolutionPhase is not abstract.
// We have to use the union here
public readonly phaseName: "EvolutionPhase" | "FormChangePhase" = "EvolutionPhase";
protected pokemon: PlayerPokemon; protected pokemon: PlayerPokemon;
protected lastLevel: number; protected lastLevel: number;

View File

@ -7,6 +7,7 @@ import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-pha
import { LevelUpPhase } from "./level-up-phase"; import { LevelUpPhase } from "./level-up-phase";
export class ExpPhase extends PlayerPartyMemberPokemonPhase { export class ExpPhase extends PlayerPartyMemberPokemonPhase {
public readonly phaseName = "ExpPhase";
private expValue: number; private expValue: number;
constructor(partyMemberIndex: number, expValue: number) { constructor(partyMemberIndex: number, expValue: number) {

View File

@ -18,7 +18,8 @@ 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";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { HitResult, PlayerPokemon, PokemonMove } from "#app/field/pokemon"; import { HitResult, PokemonMove } from "#app/field/pokemon";
import type { PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonInstantReviveModifier } from "#app/modifier/modifier"; import { PokemonInstantReviveModifier } from "#app/modifier/modifier";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
@ -35,6 +36,7 @@ import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
export class FaintPhase extends PokemonPhase { export class FaintPhase extends PokemonPhase {
public readonly phaseName = "FaintPhase";
/** /**
* Whether or not instant revive should be prevented * Whether or not instant revive should be prevented
*/ */
@ -78,10 +80,15 @@ export class FaintPhase extends PokemonPhase {
} }
} }
/** In case the current pokemon was just switched in, make sure it is counted as participating in the combat */ /**
* In case the current pokemon was just switched in, make sure it is counted as participating in the combat.
* For EXP_SHARE purposes, if the current pokemon faints as the combat ends and it was the ONLY player pokemon
* involved in combat, it needs to be counted as a participant so the other party pokemon can get their EXP,
* so the fainted pokemon has been included.
*/
for (const pokemon of globalScene.getPlayerField()) { for (const pokemon of globalScene.getPlayerField()) {
if (pokemon?.isActive(true) && pokemon.isPlayer()) { if (pokemon?.isActive() || pokemon?.isFainted()) {
globalScene.currentBattle.addParticipant(pokemon as PlayerPokemon); globalScene.currentBattle.addParticipant(pokemon);
} }
} }
@ -197,7 +204,7 @@ export class FaintPhase extends PokemonPhase {
} }
pokemon.faintCry(() => { pokemon.faintCry(() => {
if (pokemon instanceof PlayerPokemon) { if (pokemon.isPlayer()) {
pokemon.addFriendship(-FRIENDSHIP_LOSS_FROM_FAINT); pokemon.addFriendship(-FRIENDSHIP_LOSS_FROM_FAINT);
} }
pokemon.hideInfo(); pokemon.hideInfo();

View File

@ -13,6 +13,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { SpeciesFormKey } from "#enums/species-form-key"; import { SpeciesFormKey } from "#enums/species-form-key";
export class FormChangePhase extends EvolutionPhase { export class FormChangePhase extends EvolutionPhase {
public readonly phaseName = "FormChangePhase";
private formChange: SpeciesFormChange; private formChange: SpeciesFormChange;
private modal: boolean; private modal: boolean;

View File

@ -4,6 +4,7 @@ import i18next from "i18next";
import { ModifierRewardPhase } from "./modifier-reward-phase"; import { ModifierRewardPhase } from "./modifier-reward-phase";
export class GameOverModifierRewardPhase extends ModifierRewardPhase { export class GameOverModifierRewardPhase extends ModifierRewardPhase {
public readonly phaseName = "GameOverModifierRewardPhase";
doReward(): Promise<void> { doReward(): Promise<void> {
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
const newModifier = this.modifierType.newModifier(); const newModifier = this.modifierType.newModifier();

View File

@ -34,6 +34,7 @@ import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import { MessagePhase } from "./message-phase"; import { MessagePhase } from "./message-phase";
export class GameOverPhase extends BattlePhase { export class GameOverPhase extends BattlePhase {
public readonly phaseName = "GameOverPhase";
private isVictory: boolean; private isVictory: boolean;
private firstRibbons: PokemonSpecies[] = []; private firstRibbons: PokemonSpecies[] = [];

View File

@ -2,6 +2,7 @@ import { globalScene } from "#app/global-scene";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
export class HideAbilityPhase extends Phase { export class HideAbilityPhase extends Phase {
public readonly phaseName = "HideAbilityPhase";
start() { start() {
super.start(); super.start();

View File

@ -2,6 +2,7 @@ import { globalScene } from "#app/global-scene";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class HidePartyExpBarPhase extends BattlePhase { export class HidePartyExpBarPhase extends BattlePhase {
public readonly phaseName = "HidePartyExpBarPhase";
start() { start() {
super.start(); super.start();

View File

@ -12,7 +12,6 @@ import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase"; import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
export enum LearnMoveType { export enum LearnMoveType {
/** For learning a move via level-up, evolution, or other non-item-based event */ /** For learning a move via level-up, evolution, or other non-item-based event */
@ -24,6 +23,7 @@ export enum LearnMoveType {
} }
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
public readonly phaseName = "LearnMovePhase";
private moveId: MoveId; private moveId: MoveId;
private messageMode: UiMode; private messageMode: UiMode;
private learnMoveType: LearnMoveType; private learnMoveType: LearnMoveType;
@ -195,7 +195,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
pokemon.usedTMs = []; pokemon.usedTMs = [];
} }
pokemon.usedTMs.push(this.moveId); pokemon.usedTMs.push(this.moveId);
globalScene.tryRemovePhase(phase => phase instanceof SelectModifierPhase); globalScene.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
} else if (this.learnMoveType === LearnMoveType.MEMORY) { } else if (this.learnMoveType === LearnMoveType.MEMORY) {
if (this.cost !== -1) { if (this.cost !== -1) {
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
@ -205,7 +205,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
} }
globalScene.playSound("se/buy"); globalScene.playSound("se/buy");
} else { } else {
globalScene.tryRemovePhase(phase => phase instanceof SelectModifierPhase); globalScene.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
} }
} }
pokemon.setMove(index, this.moveId); pokemon.setMove(index, this.moveId);

View File

@ -4,6 +4,7 @@ import i18next from "i18next";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
export class LevelCapPhase extends FieldPhase { export class LevelCapPhase extends FieldPhase {
public readonly phaseName = "LevelCapPhase";
start(): void { start(): void {
super.start(); super.start();

View File

@ -10,6 +10,7 @@ import { NumberHolder } from "#app/utils/common";
import i18next from "i18next"; import i18next from "i18next";
export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
public readonly phaseName = "LevelUpPhase";
protected lastLevel: number; protected lastLevel: number;
protected level: number; protected level: number;
protected pokemon: PlayerPokemon = this.getPlayerPokemon(); protected pokemon: PlayerPokemon = this.getPlayerPokemon();

View File

@ -8,6 +8,7 @@ import { Phase } from "#app/phase";
* isn't already loaded (e.g. for Metronome) * isn't already loaded (e.g. for Metronome)
*/ */
export class LoadMoveAnimPhase extends Phase { export class LoadMoveAnimPhase extends Phase {
public readonly phaseName = "LoadMoveAnimPhase";
constructor(protected moveId: MoveId) { constructor(protected moveId: MoveId) {
super(); super();
} }

View File

@ -11,6 +11,7 @@ import { SelectGenderPhase } from "./select-gender-phase";
import { UnavailablePhase } from "./unavailable-phase"; import { UnavailablePhase } from "./unavailable-phase";
export class LoginPhase extends Phase { export class LoginPhase extends Phase {
public readonly phaseName = "LoginPhase";
private showText: boolean; private showText: boolean;
constructor(showText = true) { constructor(showText = true) {

View File

@ -2,6 +2,7 @@ import { globalScene } from "#app/global-scene";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
export class MessagePhase extends Phase { export class MessagePhase extends Phase {
public readonly phaseName = "MessagePhase";
private text: string; private text: string;
private callbackDelay?: number | null; private callbackDelay?: number | null;
private prompt?: boolean | null; private prompt?: boolean | null;

View File

@ -5,6 +5,10 @@ import i18next from "i18next";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class ModifierRewardPhase extends BattlePhase { export class ModifierRewardPhase extends BattlePhase {
// RibbonModifierRewardPhase extends ModifierRewardPhase and to make typescript happy
// we need to use a union type here
public readonly phaseName: "ModifierRewardPhase" | "RibbonModifierRewardPhase" | "GameOverModifierRewardPhase" =
"ModifierRewardPhase";
protected modifierType: ModifierType; protected modifierType: ModifierType;
constructor(modifierTypeFunc: ModifierTypeFunc) { constructor(modifierTypeFunc: ModifierTypeFunc) {

View File

@ -6,6 +6,7 @@ import { NumberHolder } from "#app/utils/common";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class MoneyRewardPhase extends BattlePhase { export class MoneyRewardPhase extends BattlePhase {
public readonly phaseName = "MoneyRewardPhase";
private moneyMultiplier: number; private moneyMultiplier: number;
constructor(moneyMultiplier: number) { constructor(moneyMultiplier: number) {

View File

@ -5,6 +5,8 @@ import { Phase } from "#app/phase";
* Plays the given {@linkcode MoveAnim} sequentially. * Plays the given {@linkcode MoveAnim} sequentially.
*/ */
export class MoveAnimPhase<Anim extends MoveAnim> extends Phase { export class MoveAnimPhase<Anim extends MoveAnim> extends Phase {
public readonly phaseName = "MoveAnimPhase";
constructor( constructor(
protected anim: Anim, protected anim: Anim,
protected onSubstitute = false, protected onSubstitute = false,

View File

@ -9,13 +9,13 @@ import { BooleanHolder } from "#app/utils/common";
import { MovePhase } from "#app/phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { PokemonPhase } from "#app/phases/pokemon-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveEndPhase } from "#app/phases/move-end-phase";
/** /**
* Phase for the "charging turn" of two-turn moves (e.g. Dig). * Phase for the "charging turn" of two-turn moves (e.g. Dig).
* @extends {@linkcode PokemonPhase} * @extends {@linkcode PokemonPhase}
*/ */
export class MoveChargePhase extends PokemonPhase { export class MoveChargePhase extends PokemonPhase {
public readonly phaseName = "MoveChargePhase";
/** The move instance that this phase applies */ /** The move instance that this phase applies */
public move: PokemonMove; public move: PokemonMove;
/** The field index targeted by the move (Charging moves assume single target) */ /** The field index targeted by the move (Charging moves assume single target) */
@ -62,7 +62,7 @@ export class MoveChargePhase extends PokemonPhase {
if (instantCharge.value) { if (instantCharge.value) {
// this MoveEndPhase will be duplicated by the queued MovePhase if not removed // this MoveEndPhase will be duplicated by the queued MovePhase if not removed
globalScene.tryRemovePhase(phase => phase instanceof MoveEndPhase && phase.getPokemon() === user); globalScene.tryRemovePhase(phase => phase.is("MoveEndPhase") && phase.getPokemon() === user);
// queue a new MovePhase for this move's attack phase // queue a new MovePhase for this move's attack phase
globalScene.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, false)); globalScene.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, false));
} else { } else {

View File

@ -82,6 +82,7 @@ import { DamageAchv } from "#app/system/achv";
type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier]; type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier];
export class MoveEffectPhase extends PokemonPhase { export class MoveEffectPhase extends PokemonPhase {
public readonly phaseName = "MoveEffectPhase";
public move: Move; public move: Move;
private virtual = false; private virtual = false;
protected targets: BattlerIndex[]; protected targets: BattlerIndex[];
@ -218,6 +219,7 @@ export class MoveEffectPhase extends PokemonPhase {
return; return;
} }
break; break;
// biome-ignore lint/suspicious/noFallthroughSwitchClause: The fallthrough is intentional
case HitCheckResult.NO_EFFECT: case HitCheckResult.NO_EFFECT:
globalScene.queueMessage( globalScene.queueMessage(
i18next.t(this.move.id === MoveId.SHEER_COLD ? "battle:hitResultImmune" : "battle:hitResultNoEffect", { i18next.t(this.move.id === MoveId.SHEER_COLD ? "battle:hitResultImmune" : "battle:hitResultNoEffect", {
@ -293,7 +295,8 @@ export class MoveEffectPhase extends PokemonPhase {
// If other effects were overriden, stop this phase before they can be applied // If other effects were overriden, stop this phase before they can be applied
if (overridden.value) { if (overridden.value) {
return this.end(); this.end();
return;
} }
// Lapse `MOVE_EFFECT` effects (i.e. semi-invulnerability) when applicable // Lapse `MOVE_EFFECT` effects (i.e. semi-invulnerability) when applicable
@ -742,7 +745,7 @@ export class MoveEffectPhase extends PokemonPhase {
firstTarget?: boolean | null, firstTarget?: boolean | null,
selfTarget?: boolean, selfTarget?: boolean,
): void { ): void {
return applyFilteredMoveAttrs( applyFilteredMoveAttrs(
(attr: MoveAttr) => (attr: MoveAttr) =>
attr instanceof MoveEffectAttr && attr instanceof MoveEffectAttr &&
attr.trigger === triggerType && attr.trigger === triggerType &&
@ -884,7 +887,7 @@ export class MoveEffectPhase extends PokemonPhase {
sourceBattlerIndex: user.getBattlerIndex(), sourceBattlerIndex: user.getBattlerIndex(),
}); });
if (user.isPlayer() && !target.isPlayer()) { if (user.isPlayer() && target.isEnemy()) {
globalScene.applyModifiers(DamageMoneyRewardModifier, true, user, new NumberHolder(damage)); globalScene.applyModifiers(DamageMoneyRewardModifier, true, user, new NumberHolder(damage));
} }

View File

@ -6,6 +6,7 @@ import { applyPostSummonAbAttrs, PostSummonRemoveEffectAbAttr } from "#app/data/
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
export class MoveEndPhase extends PokemonPhase { export class MoveEndPhase extends PokemonPhase {
public readonly phaseName = "MoveEndPhase";
private wasFollowUp: boolean; private wasFollowUp: boolean;
/** Targets from the preceding MovePhase */ /** Targets from the preceding MovePhase */

View File

@ -4,6 +4,7 @@ import type Pokemon from "#app/field/pokemon";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class MoveHeaderPhase extends BattlePhase { export class MoveHeaderPhase extends BattlePhase {
public readonly phaseName = "MoveHeaderPhase";
public pokemon: Pokemon; public pokemon: Pokemon;
public move: PokemonMove; public move: PokemonMove;

View File

@ -52,6 +52,7 @@ import { StatusEffect } from "#enums/status-effect";
import i18next from "i18next"; import i18next from "i18next";
export class MovePhase extends BattlePhase { export class MovePhase extends BattlePhase {
public readonly phaseName = "MovePhase";
protected _pokemon: Pokemon; protected _pokemon: Pokemon;
protected _move: PokemonMove; protected _move: PokemonMove;
protected _targets: BattlerIndex[]; protected _targets: BattlerIndex[];

View File

@ -6,7 +6,6 @@ import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-d
import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import { GameOverPhase } from "#app/phases/game-over-phase"; import { GameOverPhase } from "#app/phases/game-over-phase";
import { NewBattlePhase } from "#app/phases/new-battle-phase"; import { NewBattlePhase } from "#app/phases/new-battle-phase";
import { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import { ReturnPhase } from "#app/phases/return-phase"; import { ReturnPhase } from "#app/phases/return-phase";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase"; import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
@ -39,6 +38,7 @@ import { SelectBiomePhase } from "./select-biome-phase";
* - Queuing of the {@linkcode MysteryEncounterOptionSelectedPhase} * - Queuing of the {@linkcode MysteryEncounterOptionSelectedPhase}
*/ */
export class MysteryEncounterPhase extends Phase { export class MysteryEncounterPhase extends Phase {
public readonly phaseName = "MysteryEncounterPhase";
private readonly FIRST_DIALOGUE_PROMPT_DELAY = 300; private readonly FIRST_DIALOGUE_PROMPT_DELAY = 300;
optionSelectSettings?: OptionSelectSettings; optionSelectSettings?: OptionSelectSettings;
@ -180,6 +180,7 @@ export class MysteryEncounterPhase extends Phase {
* Any phase that is meant to follow this one MUST be queued via the onOptionSelect() logic of the selected option * Any phase that is meant to follow this one MUST be queued via the onOptionSelect() logic of the selected option
*/ */
export class MysteryEncounterOptionSelectedPhase extends Phase { export class MysteryEncounterOptionSelectedPhase extends Phase {
public readonly phaseName = "MysteryEncounterOptionSelectedPhase";
onOptionSelect: OptionPhaseCallback; onOptionSelect: OptionPhaseCallback;
constructor() { constructor() {
@ -221,6 +222,7 @@ export class MysteryEncounterOptionSelectedPhase extends Phase {
* See {@linkcode TurnEndPhase} for more details * See {@linkcode TurnEndPhase} for more details
*/ */
export class MysteryEncounterBattleStartCleanupPhase extends Phase { export class MysteryEncounterBattleStartCleanupPhase extends Phase {
public readonly phaseName = "MysteryEncounterBattleStartCleanupPhase";
/** /**
* Cleans up `TURN_END` tags, any {@linkcode PostTurnStatusEffectPhase}s, checks for Pokemon switches, then continues * Cleans up `TURN_END` tags, any {@linkcode PostTurnStatusEffectPhase}s, checks for Pokemon switches, then continues
*/ */
@ -245,8 +247,8 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
}); });
// Remove any status tick phases // Remove any status tick phases
while (globalScene.findPhase(p => p instanceof PostTurnStatusEffectPhase)) { while (globalScene.findPhase(p => p.is("PostTurnStatusEffectPhase"))) {
globalScene.tryRemovePhase(p => p instanceof PostTurnStatusEffectPhase); globalScene.tryRemovePhase(p => p.is("PostTurnStatusEffectPhase"));
} }
// The total number of Pokemon in the player's party that can legally fight // The total number of Pokemon in the player's party that can legally fight
@ -284,6 +286,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
* - Queue the {@linkcode SummonPhase}s, {@linkcode PostSummonPhase}s, etc., required to initialize the phase queue for a battle * - Queue the {@linkcode SummonPhase}s, {@linkcode PostSummonPhase}s, etc., required to initialize the phase queue for a battle
*/ */
export class MysteryEncounterBattlePhase extends Phase { export class MysteryEncounterBattlePhase extends Phase {
public readonly phaseName = "MysteryEncounterBattlePhase";
disableSwitch: boolean; disableSwitch: boolean;
constructor(disableSwitch = false) { constructor(disableSwitch = false) {
@ -513,6 +516,7 @@ export class MysteryEncounterBattlePhase extends Phase {
* - Queuing of the {@linkcode PostMysteryEncounterPhase} * - Queuing of the {@linkcode PostMysteryEncounterPhase}
*/ */
export class MysteryEncounterRewardsPhase extends Phase { export class MysteryEncounterRewardsPhase extends Phase {
public readonly phaseName = "MysteryEncounterRewardsPhase";
addHealPhase: boolean; addHealPhase: boolean;
constructor(addHealPhase = false) { constructor(addHealPhase = false) {
@ -558,7 +562,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
if (encounter.doEncounterRewards) { if (encounter.doEncounterRewards) {
encounter.doEncounterRewards(); encounter.doEncounterRewards();
} else if (this.addHealPhase) { } else if (this.addHealPhase) {
globalScene.tryRemovePhase(p => p instanceof SelectModifierPhase); globalScene.tryRemovePhase(p => p.is("SelectModifierPhase"));
globalScene.unshiftPhase( globalScene.unshiftPhase(
new SelectModifierPhase(0, undefined, { new SelectModifierPhase(0, undefined, {
fillRemaining: false, fillRemaining: false,
@ -580,6 +584,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
* - Queuing of the next wave * - Queuing of the next wave
*/ */
export class PostMysteryEncounterPhase extends Phase { export class PostMysteryEncounterPhase extends Phase {
public readonly phaseName = "PostMysteryEncounterPhase";
private readonly FIRST_DIALOGUE_PROMPT_DELAY = 750; private readonly FIRST_DIALOGUE_PROMPT_DELAY = 750;
onPostOptionSelect?: OptionPhaseCallback; onPostOptionSelect?: OptionPhaseCallback;

View File

@ -2,13 +2,14 @@ import { globalScene } from "#app/global-scene";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class NewBattlePhase extends BattlePhase { export class NewBattlePhase extends BattlePhase {
public readonly phaseName = "NewBattlePhase";
start() { start() {
super.start(); super.start();
// cull any extra `NewBattle` phases from the queue. // cull any extra `NewBattle` phases from the queue.
globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => !(phase instanceof NewBattlePhase)); globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => !phase.is("NewBattlePhase"));
// `phaseQueuePrepend` is private, so we have to use this inefficient loop. // `phaseQueuePrepend` is private, so we have to use this inefficient loop.
while (globalScene.tryRemoveUnshiftedPhase(phase => phase instanceof NewBattlePhase)) {} while (globalScene.tryRemoveUnshiftedPhase(phase => phase.is("NewBattlePhase"))) {}
globalScene.newBattle(); globalScene.newBattle();

View File

@ -4,6 +4,7 @@ import { getRandomWeatherType } from "#app/data/weather";
import { NextEncounterPhase } from "./next-encounter-phase"; import { NextEncounterPhase } from "./next-encounter-phase";
export class NewBiomeEncounterPhase extends NextEncounterPhase { export class NewBiomeEncounterPhase extends NextEncounterPhase {
public readonly phaseName = "NewBiomeEncounterPhase";
doEncounter(): void { doEncounter(): void {
globalScene.playBgm(undefined, true); globalScene.playBgm(undefined, true);

View File

@ -6,6 +6,7 @@ import { EncounterPhase } from "./encounter-phase";
* Handles generating, loading and preparing for it. * Handles generating, loading and preparing for it.
*/ */
export class NextEncounterPhase extends EncounterPhase { export class NextEncounterPhase extends EncounterPhase {
public readonly phaseName: "NextEncounterPhase" | "NewBiomeEncounterPhase" = "NextEncounterPhase";
start() { start() {
super.start(); super.start();
} }

View File

@ -11,6 +11,7 @@ import { applyPostSetStatusAbAttrs, PostSetStatusAbAttr } from "#app/data/abilit
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";
export class ObtainStatusEffectPhase extends PokemonPhase { export class ObtainStatusEffectPhase extends PokemonPhase {
public readonly phaseName = "ObtainStatusEffectPhase";
private statusEffect?: StatusEffect; private statusEffect?: StatusEffect;
private turnsRemaining?: number; private turnsRemaining?: number;
private sourceText?: string | null; private sourceText?: string | null;

View File

@ -6,6 +6,7 @@ import { Phase } from "#app/phase";
* Intended to be used as a more 1-off phase to provide exp to the party (such as during MEs), rather than cleanup a battle entirely * Intended to be used as a more 1-off phase to provide exp to the party (such as during MEs), rather than cleanup a battle entirely
*/ */
export class PartyExpPhase extends Phase { export class PartyExpPhase extends Phase {
public readonly phaseName = "PartyExpPhase";
expValue: number; expValue: number;
useWaveIndexMultiplier?: boolean; useWaveIndexMultiplier?: boolean;
pokemonParticipantIds?: Set<number>; pokemonParticipantIds?: Set<number>;

View File

@ -3,6 +3,7 @@ import { fixedInt } from "#app/utils/common";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
export class PartyHealPhase extends BattlePhase { export class PartyHealPhase extends BattlePhase {
public readonly phaseName = "PartyHealPhase";
private resumeBgm: boolean; private resumeBgm: boolean;
constructor(resumeBgm: boolean) { constructor(resumeBgm: boolean) {

View File

@ -7,6 +7,7 @@ import { PokemonAnimType } from "#enums/pokemon-anim-type";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
export class PokemonAnimPhase extends BattlePhase { export class PokemonAnimPhase extends BattlePhase {
public readonly phaseName = "PokemonAnimPhase";
/** The type of animation to play in this phase */ /** The type of animation to play in this phase */
protected key: PokemonAnimType; protected key: PokemonAnimType;
/** The Pokemon to which this animation applies */ /** The Pokemon to which this animation applies */

View File

@ -14,6 +14,7 @@ import { BattlerTagType } from "#app/enums/battler-tag-type";
import type { HealBlockTag } from "#app/data/battler-tags"; import type { HealBlockTag } from "#app/data/battler-tags";
export class PokemonHealPhase extends CommonAnimPhase { export class PokemonHealPhase extends CommonAnimPhase {
public readonly phaseName = "PokemonHealPhase";
private hpHealed: number; private hpHealed: number;
private message: string | null; private message: string | null;
private showFullHpMessage: boolean; private showFullHpMessage: boolean;

View File

@ -13,6 +13,7 @@ import i18next from "i18next";
* Used for Transform (move) and Imposter (ability) * Used for Transform (move) and Imposter (ability)
*/ */
export class PokemonTransformPhase extends PokemonPhase { export class PokemonTransformPhase extends PokemonPhase {
public readonly phaseName = "PokemonTransformPhase";
protected targetIndex: BattlerIndex; protected targetIndex: BattlerIndex;
private playSound: boolean; private playSound: boolean;

View File

@ -4,6 +4,7 @@ import type { EndCardPhase } from "./end-card-phase";
import { TitlePhase } from "./title-phase"; import { TitlePhase } from "./title-phase";
export class PostGameOverPhase extends Phase { export class PostGameOverPhase extends Phase {
public readonly phaseName = "PostGameOverPhase";
private endCardPhase?: EndCardPhase; private endCardPhase?: EndCardPhase;
constructor(endCardPhase?: EndCardPhase) { constructor(endCardPhase?: EndCardPhase) {

View File

@ -7,6 +7,7 @@ import { MysteryEncounterPostSummonTag } from "#app/data/battler-tags";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
export class PostSummonPhase extends PokemonPhase { export class PostSummonPhase extends PokemonPhase {
public readonly phaseName = "PostSummonPhase";
start() { start() {
super.start(); super.start();

View File

@ -17,6 +17,7 @@ import { BooleanHolder, NumberHolder } from "#app/utils/common";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
export class PostTurnStatusEffectPhase extends PokemonPhase { export class PostTurnStatusEffectPhase extends PokemonPhase {
public readonly phaseName = "PostTurnStatusEffectPhase";
// biome-ignore lint/complexity/noUselessConstructor: Not unnecessary as it makes battlerIndex required // biome-ignore lint/complexity/noUselessConstructor: Not unnecessary as it makes battlerIndex required
constructor(battlerIndex: BattlerIndex) { constructor(battlerIndex: BattlerIndex) {
super(battlerIndex); super(battlerIndex);

View File

@ -6,10 +6,9 @@ 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";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { MovePhase } from "./move-phase"; import type { MovePhase } from "./move-phase";
import { PokemonHealPhase } from "./pokemon-heal-phase"; import { PokemonHealPhase } from "./pokemon-heal-phase";
import { import {
applyAbAttrs, applyAbAttrs,
@ -19,6 +18,7 @@ import {
} from "#app/data/abilities/ability"; } from "#app/data/abilities/ability";
export class QuietFormChangePhase extends BattlePhase { export class QuietFormChangePhase extends BattlePhase {
public readonly phaseName = "QuietFormChangePhase";
protected pokemon: Pokemon; protected pokemon: Pokemon;
protected formChange: SpeciesFormChange; protected formChange: SpeciesFormChange;
@ -157,7 +157,7 @@ export class QuietFormChangePhase extends BattlePhase {
end(): void { end(): void {
this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED); this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED);
if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon instanceof EnemyPokemon) { if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) {
globalScene.playBgm(); globalScene.playBgm();
globalScene.unshiftPhase( globalScene.unshiftPhase(
new PokemonHealPhase(this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true), new PokemonHealPhase(this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true),
@ -168,7 +168,7 @@ export class QuietFormChangePhase extends BattlePhase {
this.pokemon.initBattleInfo(); this.pokemon.initBattleInfo();
this.pokemon.cry(); this.pokemon.cry();
const movePhase = globalScene.findPhase(p => p instanceof MovePhase && p.pokemon === this.pokemon) as MovePhase; const movePhase = globalScene.findPhase(p => p.is("MovePhase") && p.pokemon === this.pokemon) as MovePhase;
if (movePhase) { if (movePhase) {
movePhase.cancel(); movePhase.cancel();
} }

View File

@ -4,6 +4,7 @@ import { UiMode } from "#enums/ui-mode";
import { fixedInt } from "#app/utils/common"; import { fixedInt } from "#app/utils/common";
export class ReloadSessionPhase extends Phase { export class ReloadSessionPhase extends Phase {
public readonly phaseName = "ReloadSessionPhase";
private systemDataStr?: string; private systemDataStr?: string;
constructor(systemDataStr?: string) { constructor(systemDataStr?: string) {

View File

@ -7,6 +7,7 @@ import { BattlePhase } from "#app/phases/battle-phase";
* This is necessary to perform in a phase primarly to ensure that the status icon disappears at the correct time in the battle * This is necessary to perform in a phase primarly to ensure that the status icon disappears at the correct time in the battle
*/ */
export class ResetStatusPhase extends BattlePhase { export class ResetStatusPhase extends BattlePhase {
public readonly phaseName = "ResetStatusPhase";
private readonly pokemon: Pokemon; private readonly pokemon: Pokemon;
private readonly affectConfusion: boolean; private readonly affectConfusion: boolean;
private readonly reloadAssets: boolean; private readonly reloadAssets: boolean;

View File

@ -4,6 +4,7 @@ import { SwitchType } from "#enums/switch-type";
import { SwitchSummonPhase } from "./switch-summon-phase"; import { SwitchSummonPhase } from "./switch-summon-phase";
export class ReturnPhase extends SwitchSummonPhase { export class ReturnPhase extends SwitchSummonPhase {
public readonly phaseName = "ReturnPhase";
constructor(fieldIndex: number) { constructor(fieldIndex: number) {
super(SwitchType.SWITCH, fieldIndex, -1, true); super(SwitchType.SWITCH, fieldIndex, -1, true);
} }

View File

@ -15,6 +15,7 @@ import type { PlayerPokemon } from "#app/field/pokemon";
* when used by one of the player's Pokemon. * when used by one of the player's Pokemon.
*/ */
export class RevivalBlessingPhase extends BattlePhase { export class RevivalBlessingPhase extends BattlePhase {
public readonly phaseName = "RevivalBlessingPhase";
constructor(protected user: PlayerPokemon) { constructor(protected user: PlayerPokemon) {
super(); super();
} }

View File

@ -6,6 +6,7 @@ import i18next from "i18next";
import { ModifierRewardPhase } from "./modifier-reward-phase"; import { ModifierRewardPhase } from "./modifier-reward-phase";
export class RibbonModifierRewardPhase extends ModifierRewardPhase { export class RibbonModifierRewardPhase extends ModifierRewardPhase {
public readonly phaseName = "RibbonModifierRewardPhase";
private species: PokemonSpecies; private species: PokemonSpecies;
constructor(modifierTypeFunc: ModifierTypeFunc, species: PokemonSpecies) { constructor(modifierTypeFunc: ModifierTypeFunc, species: PokemonSpecies) {

View File

@ -8,6 +8,7 @@ import i18next from "i18next";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
export class ScanIvsPhase extends PokemonPhase { export class ScanIvsPhase extends PokemonPhase {
public readonly phaseName = "ScanIvsPhase";
// biome-ignore lint/complexity/noUselessConstructor: This changes `battlerIndex` to be required // biome-ignore lint/complexity/noUselessConstructor: This changes `battlerIndex` to be required
constructor(battlerIndex: BattlerIndex) { constructor(battlerIndex: BattlerIndex) {
super(battlerIndex); super(battlerIndex);

View File

@ -10,6 +10,7 @@ import { PartyHealPhase } from "./party-heal-phase";
import { SwitchBiomePhase } from "./switch-biome-phase"; import { SwitchBiomePhase } from "./switch-biome-phase";
export class SelectBiomePhase extends BattlePhase { export class SelectBiomePhase extends BattlePhase {
public readonly phaseName = "SelectBiomePhase";
start() { start() {
super.start(); super.start();

View File

@ -3,6 +3,7 @@ import { Phase } from "#app/phase";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
export class SelectChallengePhase extends Phase { export class SelectChallengePhase extends Phase {
public readonly phaseName = "SelectChallengePhase";
start() { start() {
super.start(); super.start();

View File

@ -6,6 +6,7 @@ import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
export class SelectGenderPhase extends Phase { export class SelectGenderPhase extends Phase {
public readonly phaseName = "SelectGenderPhase";
start(): void { start(): void {
super.start(); super.start();

View File

@ -32,6 +32,7 @@ import type { CustomModifierSettings } from "#app/modifier/modifier-type";
import { isNullOrUndefined, NumberHolder } from "#app/utils/common"; import { isNullOrUndefined, NumberHolder } from "#app/utils/common";
export class SelectModifierPhase extends BattlePhase { export class SelectModifierPhase extends BattlePhase {
public readonly phaseName = "SelectModifierPhase";
private rerollCount: number; private rerollCount: number;
private modifierTiers?: ModifierTier[]; private modifierTiers?: ModifierTier[];
private customModifierSettings?: CustomModifierSettings; private customModifierSettings?: CustomModifierSettings;

View File

@ -15,6 +15,7 @@ import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";
export class SelectStarterPhase extends Phase { export class SelectStarterPhase extends Phase {
public readonly phaseName = "SelectStarterPhase";
start() { start() {
super.start(); super.start();

View File

@ -8,6 +8,7 @@ import i18next from "#app/plugins/i18n";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
export class SelectTargetPhase extends PokemonPhase { export class SelectTargetPhase extends PokemonPhase {
public readonly phaseName = "SelectTargetPhase";
// biome-ignore lint/complexity/noUselessConstructor: This makes `fieldIndex` required // biome-ignore lint/complexity/noUselessConstructor: This makes `fieldIndex` required
constructor(fieldIndex: number) { constructor(fieldIndex: number) {
super(fieldIndex); super(fieldIndex);

View File

@ -3,6 +3,7 @@ import type { BattlerIndex } from "#app/battle";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
export class ShinySparklePhase extends PokemonPhase { export class ShinySparklePhase extends PokemonPhase {
public readonly phaseName = "ShinySparklePhase";
// biome-ignore lint/complexity/noUselessConstructor: This makes `battlerIndex` required // biome-ignore lint/complexity/noUselessConstructor: This makes `battlerIndex` required
constructor(battlerIndex: BattlerIndex) { constructor(battlerIndex: BattlerIndex) {
super(battlerIndex); super(battlerIndex);

View File

@ -5,6 +5,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase"; import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
export class ShowAbilityPhase extends PokemonPhase { export class ShowAbilityPhase extends PokemonPhase {
public readonly phaseName = "ShowAbilityPhase";
private passive: boolean; private passive: boolean;
private pokemonName: string; private pokemonName: string;
private abilityName: string; private abilityName: string;

Some files were not shown because too many files have changed in this diff Show More