From c36b0e27448f3decc062ad36322c42aead334f29 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 08:44:07 -0400 Subject: [PATCH 1/6] Started fixing the battle scene flyout --- src/data/abilities/ability.ts | 4 +- src/data/berry.ts | 2 + src/data/moves/move.ts | 10 +-- src/events/battle-scene.ts | 86 ++++++++++++----------- src/phases/berry-phase.ts | 2 - src/phases/move-phase.ts | 6 +- src/ui/battle-flyout.ts | 125 +++++++++++++++------------------- 7 files changed, 111 insertions(+), 124 deletions(-) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 62d6974d3a2..85f3b963a93 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -43,7 +43,7 @@ import { BATTLE_STATS, EFFECTIVE_STATS, getStatKey, Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { SwitchType } from "#enums/switch-type"; import { WeatherType } from "#enums/weather-type"; -import { BerryUsedEvent } from "#events/battle-scene"; +import { MovePPRestoredEvent } from "#events/battle-scene"; import type { EnemyPokemon, Pokemon } from "#field/pokemon"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#modifiers/modifier"; import { BerryModifierType } from "#modifiers/modifier-type"; @@ -4751,7 +4751,7 @@ export class CudChewConsumeBerryAbAttr extends AbAttr { for (const berryType of pokemon.summonData.berriesEatenLast) { getBerryEffectFunc(berryType)(pokemon); const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1); - globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(bMod)); // trigger message + globalScene.eventTarget.dispatchEvent(new MovePPRestoredEvent(bMod)); // trigger message } // uncomment to make cheek pouch work with cud chew diff --git a/src/data/berry.ts b/src/data/berry.ts index 61235b75e21..f95eee9fd95 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -6,6 +6,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { HitResult } from "#enums/hit-result"; import { type BattleStat, Stat } from "#enums/stat"; +import { MovePPRestoredEvent } from "#events/battle-scene"; import type { Pokemon } from "#field/pokemon"; import { NumberHolder, randSeedInt, toDmgValue } from "#utils/common"; import i18next from "i18next"; @@ -152,6 +153,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { berryName: getBerryName(berryType), }), ); + globalScene.eventTarget.dispatchEvent(new MovePPRestoredEvent(m)); } } break; diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 779f2d4fc76..002e46606db 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -65,7 +65,7 @@ import { import { StatusEffect } from "#enums/status-effect"; import { SwitchType } from "#enums/switch-type"; import { WeatherType } from "#enums/weather-type"; -import { MoveUsedEvent } from "#events/battle-scene"; +import { MovesetChangedEvent } from "#events/battle-scene"; import type { EnemyPokemon, Pokemon } from "#field/pokemon"; import { AttackTypeBoosterModifier, @@ -7257,7 +7257,7 @@ export class ReducePpMoveAttr extends MoveEffectAttr { const lastPpUsed = movesetMove.ppUsed; movesetMove.ppUsed = Math.min(lastPpUsed + this.reduction, movesetMove.getMovePp()); - globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(target.id, movesetMove.getMove(), movesetMove.ppUsed)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, movesetMove)); globalScene.phaseManager.queueMessage(i18next.t("battle:ppReduced", { targetName: getPokemonNameWithAffix(target), moveName: movesetMove.getName(), reduction: (movesetMove.ppUsed) - lastPpUsed })); return true; @@ -7362,11 +7362,13 @@ export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr { return false; } - // Populate summon data with a copy of the current moveset, replacing the copying move with the copied move + // Populate summon data with a copy of the current moveset, replacing the copying move with the copied move. user.summonData.moveset = user.getMoveset().slice(0); - user.summonData.moveset[thisMoveIndex] = new PokemonMove(copiedMove.id); + const newMove = new PokemonMove(copiedMove.id); + user.summonData.moveset[thisMoveIndex] = newMove; globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: copiedMove.name })); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, newMove)); return true; } diff --git a/src/events/battle-scene.ts b/src/events/battle-scene.ts index 29aee1053cd..a75224fadb2 100644 --- a/src/events/battle-scene.ts +++ b/src/events/battle-scene.ts @@ -1,7 +1,6 @@ -import type { BerryModifier } from "#modifiers/modifier"; -import type { Move } from "#moves/move"; +import type { PokemonMove } from "#moves/pokemon-move"; -/** Alias for all {@linkcode BattleScene} events */ +/** Alias for all {@linkcode BattleScene} events. */ export enum BattleSceneEventType { /** * Triggers when the corresponding setting is changed @@ -10,15 +9,11 @@ export enum BattleSceneEventType { CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeNotificationChanged", /** - * Triggers when a move is successfully used - * @see {@linkcode MoveUsedEvent} + * Triggers whenever a Pokemon's moveset is changed or altered - whether from moveset-overridding effects, + * PP consumption or restoration. + * @see {@linkcode MovesetChangedEvent} */ - MOVE_USED = "onMoveUsed", - /** - * Triggers when a berry gets successfully used - * @see {@linkcode BerryUsedEvent} - */ - BERRY_USED = "onBerryUsed", + MOVESET_CHANGED = "onMovePPChanged", /** * Triggers at the start of each new encounter @@ -44,10 +39,20 @@ export enum BattleSceneEventType { } /** + * Abstract container class for all {@linkcode BattleSceneEventType} events. + */ +abstract class BattleSceneEvent extends Event { + public declare abstract readonly type: BattleSceneEventType; // that's a mouthful! + // biome-ignore lint/complexity/noUselessConstructor: changes the type of the type field + constructor(type: BattleSceneEventType) { + super(type); + } +} /** * Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events * @extends Event */ -export class CandyUpgradeNotificationChangedEvent extends Event { +export class CandyUpgradeNotificationChangedEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED; /** The new value the setting was changed to */ public newValue: number; constructor(newValue: number) { @@ -58,61 +63,54 @@ export class CandyUpgradeNotificationChangedEvent extends Event { } /** - * Container class for {@linkcode BattleSceneEventType.MOVE_USED} events - * @extends Event + * Container class for {@linkcode BattleSceneEventType.MOVESET_CHANGED} events. \ + * Emitted whenever the moveset of any on-field Pokemon is changed, or a move's PP is increased or decreased. */ -export class MoveUsedEvent extends Event { - /** The ID of the {@linkcode Pokemon} that used the {@linkcode Move} */ +export class MovesetChangedEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.MOVESET_CHANGED; + + /** The {@linkcode Pokemon.ID | ID} of the {@linkcode Pokemon} whose moveset has changed. */ public pokemonId: number; - /** The {@linkcode Move} used */ - public move: Move; - /** The amount of PP used on the {@linkcode Move} this turn */ - public ppUsed: number; - constructor(userId: number, move: Move, ppUsed: number) { - super(BattleSceneEventType.MOVE_USED); + /** + * The {@linkcode PokemonMove} having been changed. + * Will override the corresponding slot of the moveset flyout for that Pokemon. + */ + public move: PokemonMove; - this.pokemonId = userId; + constructor(pokemonId: number, move: PokemonMove) { + super(BattleSceneEventType.MOVESET_CHANGED); + + this.pokemonId = pokemonId; this.move = move; - this.ppUsed = ppUsed; - } -} -/** - * Container class for {@linkcode BattleSceneEventType.BERRY_USED} events - * @extends Event - */ -export class BerryUsedEvent extends Event { - /** The {@linkcode BerryModifier} being used */ - public berryModifier: BerryModifier; - constructor(berry: BerryModifier) { - super(BattleSceneEventType.BERRY_USED); - - this.berryModifier = berry; } } /** - * Container class for {@linkcode BattleSceneEventType.ENCOUNTER_PHASE} events - * @extends Event + * Container class for {@linkcode BattleSceneEventType.ENCOUNTER_PHASE} events. */ -export class EncounterPhaseEvent extends Event { +export class EncounterPhaseEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.ENCOUNTER_PHASE; constructor() { super(BattleSceneEventType.ENCOUNTER_PHASE); } } + /** - * Container class for {@linkcode BattleSceneEventType.TURN_INIT} events - * @extends Event + * Container class for {@linkcode BattleSceneEventType.TURN_INIT} events. */ -export class TurnInitEvent extends Event { +export class TurnInitEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.TURN_INIT; constructor() { super(BattleSceneEventType.TURN_INIT); } } + /** * Container class for {@linkcode BattleSceneEventType.TURN_END} events * @extends Event */ -export class TurnEndEvent extends Event { +export class TurnEndEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.TURN_END; /** The amount of turns in the current battle */ public turnCount: number; constructor(turnCount: number) { diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index 941406d0b96..77c2c4b3b58 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -2,7 +2,6 @@ import { applyAbAttrs } from "#abilities/apply-ab-attrs"; import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { CommonAnim } from "#enums/move-anims-common"; -import { BerryUsedEvent } from "#events/battle-scene"; import type { Pokemon } from "#field/pokemon"; import { BerryModifier } from "#modifiers/modifier"; import { FieldPhase } from "#phases/field-phase"; @@ -65,7 +64,6 @@ export class BerryPhase extends FieldPhase { berryModifier.consumed = false; pokemon.loseHeldItem(berryModifier); } - globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); } globalScene.updateModifiers(pokemon.isPlayer()); diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 82bb6b153ef..585e2455589 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -20,7 +20,7 @@ import { MoveResult } from "#enums/move-result"; import { isIgnorePP, isIgnoreStatus, isReflected, isVirtual, MoveUseMode } from "#enums/move-use-mode"; import { PokemonType } from "#enums/pokemon-type"; import { StatusEffect } from "#enums/status-effect"; -import { MoveUsedEvent } from "#events/battle-scene"; +import { MovesetChangedEvent } from "#events/battle-scene"; import type { Pokemon } from "#field/pokemon"; import { applyMoveAttrs } from "#moves/apply-attrs"; import { frenzyMissFunc } from "#moves/move-utils"; @@ -334,7 +334,7 @@ export class MovePhase extends BattlePhase { // "commit" to using the move, deducting PP. const ppUsed = 1 + this.getPpIncreaseFromPressure(targets); this.move.usePp(ppUsed); - globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon.id, move, this.move.ppUsed)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.pokemon.id, move.id, this.move.ppUsed)); } /** @@ -640,7 +640,7 @@ export class MovePhase extends BattlePhase { // TODO: should this consider struggle? const ppUsed = isIgnorePP(this.useMode) ? 0 : 1; this.move.usePp(ppUsed); - globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), ppUsed)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.pokemon.id, this.move)); } if (this.cancelled && this.pokemon.summonData.tags.some(t => t.tagType === BattlerTagType.FRENZY)) { diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index 083dc7bbf19..584ac12528e 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -1,26 +1,26 @@ import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; -import { BerryType } from "#enums/berry-type"; import { MoveId } from "#enums/move-id"; import { UiTheme } from "#enums/ui-theme"; -import type { BerryUsedEvent, MoveUsedEvent } from "#events/battle-scene"; +import type { MovesetChangedEvent } from "#events/battle-scene"; import { BattleSceneEventType } from "#events/battle-scene"; -import type { EnemyPokemon, Pokemon } from "#field/pokemon"; -import type { Move } from "#moves/move"; +import type { Pokemon } from "#field/pokemon"; +import type { PokemonMove } from "#moves/pokemon-move"; +// biome-ignore lint/correctness/noUnusedImports: TSDoc +import type { BattleInfo } from "#ui/battle-info"; import { addTextObject, TextStyle } from "#ui/text"; import { fixedInt } from "#utils/common"; -/** Container for info about a {@linkcode Move} */ +/** Container for info about the {@linkcode PokemonMove}s having been */ interface MoveInfo { - /** The {@linkcode Move} itself */ - move: Move; - - /** The maximum PP of the {@linkcode Move} */ - maxPp: number; - /** The amount of PP used by the {@linkcode Move} */ - ppUsed: number; + /** The name of the {@linkcode Move} having been used. */ + name: string; + /** The {@linkcode PokemonMove} having been used. */ + move: PokemonMove; } +type MoveInfoTuple = [MoveInfo?, MoveInfo?, MoveInfo?, MoveInfo?]; + /** A Flyout Menu attached to each {@linkcode BattleInfo} object on the field UI */ export class BattleFlyout extends Phaser.GameObjects.Container { /** Is this object linked to a player's Pokemon? */ @@ -51,15 +51,14 @@ export class BattleFlyout extends Phaser.GameObjects.Container { /** The array of {@linkcode Phaser.GameObjects.Text} objects which are drawn on the flyout */ private flyoutText: Phaser.GameObjects.Text[] = new Array(4); - /** The array of {@linkcode MoveInfo} used to track moves for the {@linkcode Pokemon} linked to the flyout */ - private moveInfo: MoveInfo[] = []; + /** An array of {@linkcode MoveInfo}s used to track moves for the {@linkcode Pokemon} linked to the flyout. */ + private moveInfo: MoveInfoTuple = []; /** Current state of the flyout's visibility */ public flyoutVisible = false; // Stores callbacks in a variable so they can be unsubscribed from when destroyed - private readonly onMoveUsedEvent = (event: Event) => this.onMoveUsed(event); - private readonly onBerryUsedEvent = (event: Event) => this.onBerryUsed(event); + private readonly onMovesetChangedEvent = (event: MovesetChangedEvent) => this.onMovesetChanged(event); constructor(player: boolean) { super(globalScene, 0, 0); @@ -123,79 +122,67 @@ export class BattleFlyout extends Phaser.GameObjects.Container { } /** - * Links the given {@linkcode Pokemon} and subscribes to the {@linkcode BattleSceneEventType.MOVE_USED} event - * @param pokemon {@linkcode Pokemon} to link to this flyout + * Link the given {@linkcode Pokemon} to this flyout and subscribe to the {@linkcode BattleSceneEventType.MOVESET_CHANGED} event. + * @param pokemon - The {@linkcode Pokemon} to link to this flyout */ - initInfo(pokemon: EnemyPokemon) { + public initInfo(pokemon: Pokemon): void { this.pokemon = pokemon; this.name = `Flyout ${getPokemonNameWithAffix(this.pokemon)}`; this.flyoutParent.name = `Flyout Parent ${getPokemonNameWithAffix(this.pokemon)}`; - globalScene.eventTarget.addEventListener(BattleSceneEventType.MOVE_USED, this.onMoveUsedEvent); - globalScene.eventTarget.addEventListener(BattleSceneEventType.BERRY_USED, this.onBerryUsedEvent); + globalScene.eventTarget.addEventListener(BattleSceneEventType.MOVESET_CHANGED, this.onMovesetChangedEvent); } - /** Sets and formats the text property for all {@linkcode Phaser.GameObjects.Text} in the flyoutText array */ - private setText() { - for (let i = 0; i < this.flyoutText.length; i++) { - const flyoutText = this.flyoutText[i]; - const moveInfo = this.moveInfo[i]; - - if (!moveInfo) { - continue; - } - - const currentPp = moveInfo.maxPp - moveInfo.ppUsed; - flyoutText.text = `${moveInfo.move.name} ${currentPp}/${moveInfo.maxPp}`; - } - } - - /** Updates all of the {@linkcode MoveInfo} objects in the moveInfo array */ - private onMoveUsed(event: Event) { - const moveUsedEvent = event as MoveUsedEvent; - if (!moveUsedEvent || moveUsedEvent.pokemonId !== this.pokemon?.id || moveUsedEvent.move.id === MoveId.STRUGGLE) { - // Ignore Struggle + /** + * Set and formats the text property for all {@linkcode Phaser.GameObjects.Text} in the flyoutText array. + * @param index - The 0-indexed position of the flyout text object to update + */ + private updateText(index: number) { + const flyoutText = this.flyoutText[index]; + const moveInfo = this.moveInfo[index]; + if (!moveInfo) { return; } - const foundInfo = this.moveInfo.find(x => x?.move.id === moveUsedEvent.move.id); - if (foundInfo) { - foundInfo.ppUsed = moveUsedEvent.ppUsed; - } else { - this.moveInfo.push({ - move: moveUsedEvent.move, - maxPp: moveUsedEvent.move.pp, - ppUsed: moveUsedEvent.ppUsed, - }); - } - - this.setText(); + const maxPP = moveInfo.move.getMovePp(); + const currentPp = -moveInfo.move.ppUsed; + flyoutText.text = `${moveInfo.name} ${currentPp}/${maxPP}`; } - private onBerryUsed(event: Event) { - const berryUsedEvent = event as BerryUsedEvent; + /** + * Update the corresponding {@linkcode MoveInfo} object in the moveInfo array. + * @param event - The {@linkcode MovesetChangedEvent} having been emitted + */ + private onMovesetChanged(event: MovesetChangedEvent): void { + // Ignore other Pokemon's moves as well as Struggle and MoveId.NONE if ( - !berryUsedEvent || - berryUsedEvent.berryModifier.pokemonId !== this.pokemon?.id || - berryUsedEvent.berryModifier.berryType !== BerryType.LEPPA + event.pokemonId !== this.pokemon.id || + event.move.moveId === MoveId.NONE || + event.move.moveId === MoveId.STRUGGLE ) { - // We only care about Leppa berries return; } - const foundInfo = this.moveInfo.find(info => info.ppUsed === info.maxPp); - if (!foundInfo) { - // This will only happen on a de-sync of PP tracking - return; + // If we already have a move in that slot, update the corresponding slot of the Pokemon's moveset. + const index = this.pokemon.getMoveset().indexOf(event.move); + if (index === -1) { + console.error("Updated move passed to move flyout was undefined!"); + } + if (this.moveInfo[index]) { + this.moveInfo[index].move = event.move; + } else { + this.moveInfo[index] = { + name: event.move.getMove().name, + move: event.move, + }; } - foundInfo.ppUsed = Math.max(foundInfo.ppUsed - 10, 0); - this.setText(); + this.updateText(index); } /** Animates the flyout to either show or hide it by applying a fade and translation */ - toggleFlyout(visible: boolean): void { + public toggleFlyout(visible: boolean): void { this.flyoutVisible = visible; globalScene.tweens.add({ @@ -207,9 +194,9 @@ export class BattleFlyout extends Phaser.GameObjects.Container { }); } - destroy(fromScene?: boolean): void { - globalScene.eventTarget.removeEventListener(BattleSceneEventType.MOVE_USED, this.onMoveUsedEvent); - globalScene.eventTarget.removeEventListener(BattleSceneEventType.BERRY_USED, this.onBerryUsedEvent); + /** Destroy this element and remove all associated listeners. */ + public destroy(fromScene?: boolean): void { + globalScene.eventTarget.removeEventListener(BattleSceneEventType.MOVESET_CHANGED, this.onMovesetChangedEvent); super.destroy(fromScene); } From d21434c32ad7e4a074fb468dd6b2c1127d89f187 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 10:17:10 -0400 Subject: [PATCH 2/6] Removed unused `turnInitEvent --- src/events/battle-scene.ts | 15 --------------- src/phases/turn-init-phase.ts | 3 --- 2 files changed, 18 deletions(-) diff --git a/src/events/battle-scene.ts b/src/events/battle-scene.ts index a75224fadb2..5945e8f849c 100644 --- a/src/events/battle-scene.ts +++ b/src/events/battle-scene.ts @@ -20,11 +20,6 @@ export enum BattleSceneEventType { * @see {@linkcode EncounterPhaseEvent} */ ENCOUNTER_PHASE = "onEncounterPhase", - /** - * Triggers on the first turn of a new battle - * @see {@linkcode TurnInitEvent} - */ - TURN_INIT = "onTurnInit", /** * Triggers after a turn ends in battle * @see {@linkcode TurnEndEvent} @@ -95,16 +90,6 @@ export class EncounterPhaseEvent extends BattleSceneEvent { } } -/** - * Container class for {@linkcode BattleSceneEventType.TURN_INIT} events. - */ -export class TurnInitEvent extends BattleSceneEvent { - declare type: BattleSceneEventType.TURN_INIT; - constructor() { - super(BattleSceneEventType.TURN_INIT); - } -} - /** * Container class for {@linkcode BattleSceneEventType.TURN_END} events * @extends Event diff --git a/src/phases/turn-init-phase.ts b/src/phases/turn-init-phase.ts index b2ab096102c..aacfbed4435 100644 --- a/src/phases/turn-init-phase.ts +++ b/src/phases/turn-init-phase.ts @@ -1,6 +1,5 @@ import { globalScene } from "#app/global-scene"; import { BattlerIndex } from "#enums/battler-index"; -import { TurnInitEvent } from "#events/battle-scene"; import type { PlayerPokemon } from "#field/pokemon"; import { handleMysteryEncounterBattleStartEffects, @@ -46,8 +45,6 @@ export class TurnInitPhase extends FieldPhase { } }); - globalScene.eventTarget.dispatchEvent(new TurnInitEvent()); - handleMysteryEncounterBattleStartEffects(); // If true, will skip remainder of current phase (and not queue CommandPhases etc.) From 6cfc35f823ca9259843f082f62ed848e6ffa447d Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 11:31:59 -0400 Subject: [PATCH 3/6] Continued fixing up the battle show thingy --- src/battle-scene.ts | 12 ++--- src/data/abilities/ability.ts | 3 -- src/data/berry.ts | 4 +- src/events/battle-scene.ts | 54 +++++++++++++++++----- src/field/pokemon.ts | 7 ++- src/phases/move-phase.ts | 4 +- src/phases/pokemon-transform-phase.ts | 28 ++++++++++-- src/ui/battle-flyout.ts | 66 +++++++++++++++++++++------ 8 files changed, 132 insertions(+), 46 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 62351c4a833..92b2dfadea9 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -71,6 +71,7 @@ import type { TrainerSlot } from "#enums/trainer-slot"; import { TrainerType } from "#enums/trainer-type"; import { TrainerVariant } from "#enums/trainer-variant"; import { UiTheme } from "#enums/ui-theme"; +import type { BattleSceneEvent } from "#events/battle-scene"; import { NewArenaEvent } from "#events/battle-scene"; import { Arena, ArenaBase } from "#field/arena"; import { DamageNumberHandler } from "#field/damage-number-handler"; @@ -125,6 +126,7 @@ import { vouchers } from "#system/voucher"; import { trainerConfigs } from "#trainers/trainer-config"; import type { HeldModifierConfig } from "#types/held-modifier-config"; import type { Localizable } from "#types/locales"; +import type { TypedEventTarget } from "#types/typed-event-target"; import { AbilityBar } from "#ui/ability-bar"; import { ArenaFlyout } from "#ui/arena-flyout"; import { CandyBar } from "#ui/candy-bar"; @@ -327,15 +329,9 @@ export class BattleScene extends SceneBase { public eventManager: TimedEventManager; /** - * Allows subscribers to listen for events - * - * Current Events: - * - {@linkcode BattleSceneEventType.MOVE_USED} {@linkcode MoveUsedEvent} - * - {@linkcode BattleSceneEventType.TURN_INIT} {@linkcode TurnInitEvent} - * - {@linkcode BattleSceneEventType.TURN_END} {@linkcode TurnEndEvent} - * - {@linkcode BattleSceneEventType.NEW_ARENA} {@linkcode NewArenaEvent} + * Allows subscribers to listen for events. */ - public readonly eventTarget: EventTarget = new EventTarget(); + public readonly eventTarget: TypedEventTarget = new EventTarget(); constructor() { super("battle"); diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 85f3b963a93..59f73ccfc57 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -43,7 +43,6 @@ import { BATTLE_STATS, EFFECTIVE_STATS, getStatKey, Stat } from "#enums/stat"; import { StatusEffect } from "#enums/status-effect"; import { SwitchType } from "#enums/switch-type"; import { WeatherType } from "#enums/weather-type"; -import { MovePPRestoredEvent } from "#events/battle-scene"; import type { EnemyPokemon, Pokemon } from "#field/pokemon"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#modifiers/modifier"; import { BerryModifierType } from "#modifiers/modifier-type"; @@ -4750,8 +4749,6 @@ export class CudChewConsumeBerryAbAttr extends AbAttr { // This doesn't count as "eating" a berry (for unnerve/stuff cheeks/unburden) as no item is consumed. for (const berryType of pokemon.summonData.berriesEatenLast) { getBerryEffectFunc(berryType)(pokemon); - const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1); - globalScene.eventTarget.dispatchEvent(new MovePPRestoredEvent(bMod)); // trigger message } // uncomment to make cheek pouch work with cud chew diff --git a/src/data/berry.ts b/src/data/berry.ts index f95eee9fd95..c08634301f6 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -6,7 +6,7 @@ import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; import { HitResult } from "#enums/hit-result"; import { type BattleStat, Stat } from "#enums/stat"; -import { MovePPRestoredEvent } from "#events/battle-scene"; +import { MovesetChangedEvent } from "#events/battle-scene"; import type { Pokemon } from "#field/pokemon"; import { NumberHolder, randSeedInt, toDmgValue } from "#utils/common"; import i18next from "i18next"; @@ -153,7 +153,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { berryName: getBerryName(berryType), }), ); - globalScene.eventTarget.dispatchEvent(new MovePPRestoredEvent(m)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(consumer.id, ppRestoreMove)); } } break; diff --git a/src/events/battle-scene.ts b/src/events/battle-scene.ts index 5945e8f849c..fdafb9a1d30 100644 --- a/src/events/battle-scene.ts +++ b/src/events/battle-scene.ts @@ -1,33 +1,42 @@ +// biome-ignore lint/correctness/noUnusedImports: TSDoc +import type { PokemonSummonData } from "#data/pokemon-data"; import type { PokemonMove } from "#moves/pokemon-move"; -/** Alias for all {@linkcode BattleScene} events. */ +/** Enum comprising all {@linkcode BattleScene} events that can be emitted. */ export enum BattleSceneEventType { /** - * Triggers when the corresponding setting is changed + * Emitted when the corresponding setting is changed * @see {@linkcode CandyUpgradeNotificationChangedEvent} */ CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeNotificationChanged", /** - * Triggers whenever a Pokemon's moveset is changed or altered - whether from moveset-overridding effects, + * Emitted whenever a Pokemon's moveset is changed or altered - whether from moveset-overridding effects, * PP consumption or restoration. * @see {@linkcode MovesetChangedEvent} */ - MOVESET_CHANGED = "onMovePPChanged", + MOVESET_CHANGED = "onMovesetChanged", /** - * Triggers at the start of each new encounter + * Emitted whenever the {@linkcode PokemonSummonData} of any {@linkcode Pokemon} is reset to its initial state + * (such as immediately before a switch-out). + * @see {@linkcode SummonDataResetEvent} + */ + SUMMON_DATA_RESET = "onSummonDataReset", + + /** + * Emitted at the start of each new encounter * @see {@linkcode EncounterPhaseEvent} */ ENCOUNTER_PHASE = "onEncounterPhase", /** - * Triggers after a turn ends in battle + * Emitted after a turn ends in battle * @see {@linkcode TurnEndEvent} */ TURN_END = "onTurnEnd", /** - * Triggers when a new {@linkcode Arena} is created during initialization + * Emitted when a new {@linkcode Arena} is created during initialization * @see {@linkcode NewArenaEvent} */ NEW_ARENA = "onNewArena", @@ -42,9 +51,12 @@ abstract class BattleSceneEvent extends Event { constructor(type: BattleSceneEventType) { super(type); } -} /** +} + +export type { BattleSceneEvent }; + +/** * Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events - * @extends Event */ export class CandyUpgradeNotificationChangedEvent extends BattleSceneEvent { declare type: BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED; @@ -59,7 +71,7 @@ export class CandyUpgradeNotificationChangedEvent extends BattleSceneEvent { /** * Container class for {@linkcode BattleSceneEventType.MOVESET_CHANGED} events. \ - * Emitted whenever the moveset of any on-field Pokemon is changed, or a move's PP is increased or decreased. + * Emitted whenever the moveset of any {@linkcode Pokemon} is changed, or a move's PP is increased or decreased. */ export class MovesetChangedEvent extends BattleSceneEvent { declare type: BattleSceneEventType.MOVESET_CHANGED; @@ -80,6 +92,24 @@ export class MovesetChangedEvent extends BattleSceneEvent { } } +/** + * Container class for {@linkcode BattleSceneEventType.SUMMON_DATA_RESET} events. \ + * Emitted whenever the {@linkcode PokemonSummonData} of any {@linkcode Pokemon} is reset to its initial state + * (such as immediately before a switch-out). + */ +export class SummonDataResetEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.SUMMON_DATA_RESET; + + /** The {@linkcode Pokemon.ID | ID} of the {@linkcode Pokemon} whose data has been reset. */ + public pokemonId: number; + + constructor(pokemonId: number) { + super(BattleSceneEventType.SUMMON_DATA_RESET); + + this.pokemonId = pokemonId; + } +} + /** * Container class for {@linkcode BattleSceneEventType.ENCOUNTER_PHASE} events. */ @@ -106,9 +136,9 @@ export class TurnEndEvent extends BattleSceneEvent { } /** * Container class for {@linkcode BattleSceneEventType.NEW_ARENA} events - * @extends Event */ -export class NewArenaEvent extends Event { +export class NewArenaEvent extends BattleSceneEvent { + declare type: BattleSceneEventType.NEW_ARENA; constructor() { super(BattleSceneEventType.NEW_ARENA); } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 32edd721cd9..5fc23ae51fd 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -108,6 +108,7 @@ import { SwitchType } from "#enums/switch-type"; import type { TrainerSlot } from "#enums/trainer-slot"; import { UiMode } from "#enums/ui-mode"; import { WeatherType } from "#enums/weather-type"; +import { SummonDataResetEvent } from "#events/battle-scene"; import { doShinySparkleAnim } from "#field/anims"; import { BaseStatModifier, @@ -1828,7 +1829,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { /** * Return all the {@linkcode PokemonMove}s that make up this Pokemon's moveset. * Takes into account player/enemy moveset overrides (which will also override PP count). - * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode Moves.TRANSFORM | Transform}; default `false` + * @param ignoreOverride - Whether to ignore any overrides caused by {@linkcode MoveId.TRANSFORM | Transform}; default `false` * @returns An array of {@linkcode PokemonMove}, as described above. */ getMoveset(ignoreOverride = false): PokemonMove[] { @@ -5084,6 +5085,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { this.summonData.speciesForm = null; this.updateFusionPalette(); } + + // Emit an event to reset all temporary moveset overrides due to Mimic/Transform wearing off. + globalScene.eventTarget.dispatchEvent(new SummonDataResetEvent(this.id)); + this.summonData = new PokemonSummonData(); this.tempSummonData = new PokemonTempSummonData(); this.summonData.illusion = illusion; diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 585e2455589..c49a5a8ed17 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -334,7 +334,7 @@ export class MovePhase extends BattlePhase { // "commit" to using the move, deducting PP. const ppUsed = 1 + this.getPpIncreaseFromPressure(targets); this.move.usePp(ppUsed); - globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.pokemon.id, move.id, this.move.ppUsed)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.pokemon.id, this.move)); } /** @@ -637,7 +637,7 @@ export class MovePhase extends BattlePhase { } if (this.failed) { - // TODO: should this consider struggle? + // TODO: should this consider struggle and pressure? const ppUsed = isIgnorePP(this.useMode) ? 0 : 1; this.move.usePp(ppUsed); globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.pokemon.id, this.move)); diff --git a/src/phases/pokemon-transform-phase.ts b/src/phases/pokemon-transform-phase.ts index 143c47886b6..9451d5bffdb 100644 --- a/src/phases/pokemon-transform-phase.ts +++ b/src/phases/pokemon-transform-phase.ts @@ -4,6 +4,7 @@ import type { BattlerIndex } from "#enums/battler-index"; import { BattlerTagType } from "#enums/battler-tag-type"; import { MoveId } from "#enums/move-id"; import { BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat"; +import { MovesetChangedEvent } from "#events/battle-scene"; import { PokemonMove } from "#moves/pokemon-move"; import { PokemonPhase } from "#phases/pokemon-phase"; import i18next from "i18next"; @@ -50,12 +51,14 @@ export class PokemonTransformPhase extends PokemonPhase { user.setStatStage(s, target.getStatStage(s)); } - user.summonData.moveset = target.getMoveset().map(m => { - if (m) { + user.summonData.moveset = target.getMoveset().map(oldMove => { + if (oldMove) { // If PP value is less than 5, do nothing. If greater, we need to reduce the value to 5. - return new PokemonMove(m.moveId, 0, 0, Math.min(m.getMove().pp, 5)); + const newMove = new PokemonMove(oldMove.moveId, 0, 0, Math.min(oldMove.getMove().pp, 5)); + this.emitMovesetChange(oldMove, newMove); + return newMove; } - console.warn(`Transform: somehow iterating over a ${m} value when copying moveset!`); + console.warn(`Transform: somehow iterating over a ${oldMove} value when copying moveset!`); return new PokemonMove(MoveId.NONE); }); @@ -86,4 +89,21 @@ export class PokemonTransformPhase extends PokemonPhase { Promise.allSettled(promises).then(() => this.end()); } + + /** + * Emit an event upon transforming and changing movesets. + * @param origMovee - The target's original {@linkcode PokemonMove} being copied + * @param copiedMove - The new {@linkcode PokemonMove} being added to the user's moveset + */ + private emitMovesetChange(origMove: PokemonMove, copiedMove: PokemonMove): void { + const user = this.getPokemon(); + const target = globalScene.getField()[this.targetIndex]; + + // Dispatch an event for the user's moveset temporarily changing. + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(user.id, copiedMove)); + // If the user is a player having transformed into an enemy, permanently reveal the corresponding move in their moveset. + if (user.isPlayer() && target.isEnemy()) { + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, origMove)); + } + } } diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index 584ac12528e..f7442b4de55 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene"; import { getPokemonNameWithAffix } from "#app/messages"; import { MoveId } from "#enums/move-id"; import { UiTheme } from "#enums/ui-theme"; -import type { MovesetChangedEvent } from "#events/battle-scene"; +import type { MovesetChangedEvent, SummonDataResetEvent } from "#events/battle-scene"; import { BattleSceneEventType } from "#events/battle-scene"; import type { Pokemon } from "#field/pokemon"; import type { PokemonMove } from "#moves/pokemon-move"; @@ -11,7 +11,7 @@ import type { BattleInfo } from "#ui/battle-info"; import { addTextObject, TextStyle } from "#ui/text"; import { fixedInt } from "#utils/common"; -/** Container for info about the {@linkcode PokemonMove}s having been */ +/** Container for info about a given {@linkcode PokemonMove} having been used */ interface MoveInfo { /** The name of the {@linkcode Move} having been used. */ name: string; @@ -19,14 +19,22 @@ interface MoveInfo { move: PokemonMove; } +/** + * A 4-length tuple consisting of all moves that each {@linkcode Pokemon} has used in the given battle. + * Entries that are `undefined` indicate moves which have not been used yet. + */ type MoveInfoTuple = [MoveInfo?, MoveInfo?, MoveInfo?, MoveInfo?]; -/** A Flyout Menu attached to each {@linkcode BattleInfo} object on the field UI */ +/** + * A Flyout Menu attached to each Pokemon's {@linkcode BattleInfo} object, + * showing all revealed moves and their current PP counts. + * @todo Stop tracking player move usages + */ export class BattleFlyout extends Phaser.GameObjects.Container { /** Is this object linked to a player's Pokemon? */ private player: boolean; - /** The Pokemon this object is linked to */ + /** The Pokemon this object is linked to. */ private pokemon: Pokemon; /** The restricted width of the flyout which should be drawn to */ @@ -53,12 +61,20 @@ export class BattleFlyout extends Phaser.GameObjects.Container { private flyoutText: Phaser.GameObjects.Text[] = new Array(4); /** An array of {@linkcode MoveInfo}s used to track moves for the {@linkcode Pokemon} linked to the flyout. */ private moveInfo: MoveInfoTuple = []; + /** + * An array of {@linkcode MoveInfo}s used to track move slots + * temporarily overridden by {@linkcode MoveId.TRANSFORM} or {@linkcode MoveId.MIMIC}. + * + * Reset once {@linkcode pokemon} switches out via a {@linkcode SummonDataResetEvent}. + */ + private tempMoveInfo: MoveInfoTuple = []; /** Current state of the flyout's visibility */ public flyoutVisible = false; // Stores callbacks in a variable so they can be unsubscribed from when destroyed private readonly onMovesetChangedEvent = (event: MovesetChangedEvent) => this.onMovesetChanged(event); + private readonly onMovesetRestoredEvent = (event: SummonDataResetEvent) => this.onMovesetRestored(event); constructor(player: boolean) { super(globalScene, 0, 0); @@ -138,13 +154,14 @@ export class BattleFlyout extends Phaser.GameObjects.Container { * Set and formats the text property for all {@linkcode Phaser.GameObjects.Text} in the flyoutText array. * @param index - The 0-indexed position of the flyout text object to update */ - private updateText(index: number) { - const flyoutText = this.flyoutText[index]; - const moveInfo = this.moveInfo[index]; + private updateText(index: number): void { + // Use temp move info if present, or else the regular move info. + const moveInfo = this.tempMoveInfo[index] ?? this.moveInfo[index]; if (!moveInfo) { return; } + const flyoutText = this.flyoutText[index]; const maxPP = moveInfo.move.getMovePp(); const currentPp = -moveInfo.move.ppUsed; flyoutText.text = `${moveInfo.name} ${currentPp}/${maxPP}`; @@ -164,15 +181,20 @@ export class BattleFlyout extends Phaser.GameObjects.Container { return; } - // If we already have a move in that slot, update the corresponding slot of the Pokemon's moveset. - const index = this.pokemon.getMoveset().indexOf(event.move); + // Push to either the temporary or permanent move arrays, depending on which array the move was found in. + const isPermanent = this.pokemon.getMoveset(true).includes(event.move); + const infoArray = isPermanent ? this.moveInfo : this.tempMoveInfo; + + const index = this.pokemon.getMoveset(isPermanent).indexOf(event.move); if (index === -1) { - console.error("Updated move passed to move flyout was undefined!"); + throw new Error("Updated move passed to move flyout was not found in moveset!"); } - if (this.moveInfo[index]) { - this.moveInfo[index].move = event.move; + + // Update the corresponding slot in the info array with either a new entry or an updated PP reading. + if (infoArray[index]) { + infoArray[index].move = event.move; } else { - this.moveInfo[index] = { + infoArray[index] = { name: event.move.getMove().name, move: event.move, }; @@ -181,7 +203,23 @@ export class BattleFlyout extends Phaser.GameObjects.Container { this.updateText(index); } - /** Animates the flyout to either show or hide it by applying a fade and translation */ + /** + * Reset the linked Pokemon's temporary moveset override when it is switched out. + * @param event - The {@linkcode SummonDataResetEvent} having been emitted + */ + private onMovesetRestored(event: SummonDataResetEvent): void { + if (event.pokemonId !== this.pokemon.id) { + // Wrong pokemon + return; + } + + this.tempMoveInfo = []; + } + + /** + * Animate the flyout to either show or hide the modal. + * @param visible - Whether the the flyout should be shown + */ public toggleFlyout(visible: boolean): void { this.flyoutVisible = visible; From 07f25c777184b5c387f076ff7d70babc5196fef4 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 12:44:50 -0400 Subject: [PATCH 4/6] Renamed some battle flyout stuff --- src/ui/battle-flyout.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index f7442b4de55..c41ab7c0798 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -74,7 +74,7 @@ export class BattleFlyout extends Phaser.GameObjects.Container { // Stores callbacks in a variable so they can be unsubscribed from when destroyed private readonly onMovesetChangedEvent = (event: MovesetChangedEvent) => this.onMovesetChanged(event); - private readonly onMovesetRestoredEvent = (event: SummonDataResetEvent) => this.onMovesetRestored(event); + private readonly onSummonDataResetEvent = (event: SummonDataResetEvent) => this.onSummonDataReset(event); constructor(player: boolean) { super(globalScene, 0, 0); @@ -148,6 +148,7 @@ export class BattleFlyout extends Phaser.GameObjects.Container { this.flyoutParent.name = `Flyout Parent ${getPokemonNameWithAffix(this.pokemon)}`; globalScene.eventTarget.addEventListener(BattleSceneEventType.MOVESET_CHANGED, this.onMovesetChangedEvent); + globalScene.eventTarget.addEventListener(BattleSceneEventType.SUMMON_DATA_RESET, this.onSummonDataResetEvent); } /** @@ -207,7 +208,7 @@ export class BattleFlyout extends Phaser.GameObjects.Container { * Reset the linked Pokemon's temporary moveset override when it is switched out. * @param event - The {@linkcode SummonDataResetEvent} having been emitted */ - private onMovesetRestored(event: SummonDataResetEvent): void { + private onSummonDataReset(event: SummonDataResetEvent): void { if (event.pokemonId !== this.pokemon.id) { // Wrong pokemon return; @@ -235,6 +236,7 @@ export class BattleFlyout extends Phaser.GameObjects.Container { /** Destroy this element and remove all associated listeners. */ public destroy(fromScene?: boolean): void { globalScene.eventTarget.removeEventListener(BattleSceneEventType.MOVESET_CHANGED, this.onMovesetChangedEvent); + globalScene.eventTarget.removeEventListener(BattleSceneEventType.SUMMON_DATA_RESET, this.onSummonDataResetEvent); super.destroy(fromScene); } From 1c73b7c269f581a98adf399b302a86e79154bb85 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 13:22:47 -0400 Subject: [PATCH 5/6] Fixed battler thingy --- src/data/moves/move.ts | 4 ++-- src/field/pokemon.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 002e46606db..976a93a4935 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -7257,8 +7257,8 @@ export class ReducePpMoveAttr extends MoveEffectAttr { const lastPpUsed = movesetMove.ppUsed; movesetMove.ppUsed = Math.min(lastPpUsed + this.reduction, movesetMove.getMovePp()); - globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, movesetMove)); globalScene.phaseManager.queueMessage(i18next.t("battle:ppReduced", { targetName: getPokemonNameWithAffix(target), moveName: movesetMove.getName(), reduction: (movesetMove.ppUsed) - lastPpUsed })); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, movesetMove)); return true; } @@ -7368,7 +7368,7 @@ export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr { user.summonData.moveset[thisMoveIndex] = newMove; globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: copiedMove.name })); - globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(target.id, newMove)); + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(user.id, newMove)); return true; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 5fc23ae51fd..1ef1488e9a8 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -108,7 +108,7 @@ import { SwitchType } from "#enums/switch-type"; import type { TrainerSlot } from "#enums/trainer-slot"; import { UiMode } from "#enums/ui-mode"; import { WeatherType } from "#enums/weather-type"; -import { SummonDataResetEvent } from "#events/battle-scene"; +import { MovesetChangedEvent, SummonDataResetEvent } from "#events/battle-scene"; import { doShinySparkleAnim } from "#field/anims"; import { BaseStatModifier, @@ -2836,6 +2836,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { if (this.summonData.moveset) { this.summonData.moveset[moveIndex] = move; } + globalScene.eventTarget.dispatchEvent(new MovesetChangedEvent(this.id, move)); } /** From 54ec5904f0267d48f06b91c80f91b9f362cc9659 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 25 Jul 2025 13:34:22 -0400 Subject: [PATCH 6/6] Re-added typed event target --- src/@types/typed-event-target.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/@types/typed-event-target.ts diff --git a/src/@types/typed-event-target.ts b/src/@types/typed-event-target.ts new file mode 100644 index 00000000000..2c38a6812d6 --- /dev/null +++ b/src/@types/typed-event-target.ts @@ -0,0 +1,17 @@ +/** + * Interface restricting the events emitted by an {@linkcode EventTarget} to a certain kind of {@linkcode Event}. + * @typeParam T - The type to restrict the interface's access; must extend from {@linkcode Event} + */ +export interface TypedEventTarget extends EventTarget { + dispatchEvent(event: T): boolean; + addEventListener( + event: T["type"], + callback: EventListenerOrEventListenerObject | null, + options?: AddEventListenerOptions | boolean, + ): void; + removeEventListener( + type: T["type"], + callback: EventListenerOrEventListenerObject | null, + options?: EventListenerOptions | boolean, + ): void; +}