Adding Event Listeners in Pokestar Battle System
Event listeners are the core mechanism for abilities, effects, and held items to respond to battle events.
Registration Pattern
All battle components use registerListenerFunction to subscribe to events:
const listenerId = battle.registerListenerFunction({
eventName: battleEventEnum.BEFORE_DAMAGE,
callback: (args) => {
// Your logic here
},
conditionCallback: getIsTargetPokemonCallback(target),
});
Always store the listenerId and unregister in the remove function:
abilityAdd({ battle, target }) {
return {
listenerId: this.registerListenerFunction({...}),
};
},
abilityRemove({ battle, properties }) {
battle.unregisterListener(properties.listenerId);
}
Class-Level vs Battle-Level Registration
Class-Level (Recommended for Abilities/Held Items)
Abilities and Held Items have this.registerListenerFunction which:
- •Automatically checks if the component is still active
- •Provides the component instance in callback args
// In an Ability
this.registerListenerFunction({
battle,
target,
eventName: battleEventEnum.AFTER_DAMAGE_DEALT,
callback: ({ abilityInstance }) => {
// abilityInstance.data contains stored properties
},
conditionCallback: getIsSourcePokemonCallback(target),
});
Battle-Level (For Effects)
Effects use battle.registerListenerFunction directly:
// In an Effect
battle.registerListenerFunction({
eventName: battleEventEnum.BEFORE_DAMAGE,
callback: (args) => {
// Effect logic
},
conditionCallback: getIsTargetPokemonCallback(target),
});
Common Battle Events
| Event | Description | Key Args |
|---|---|---|
BATTLE_BEGIN | Start of battle | battle |
TURN_BEGIN | Start of each turn | battle |
TURN_END | End of each turn | battle |
BEFORE_MOVE | Before a move executes | source, moveId, targets |
AFTER_MOVE | After a move executes | source, moveId, targets |
BEFORE_DAMAGE | Before damage is dealt | damage, target, source, type |
AFTER_DAMAGE_DEALT | After damage is dealt | damage, target, source, type |
BEFORE_EFFECT_ADD | Before an effect is applied | effectId, target, canAdd |
AFTER_EFFECT_ADD | After an effect is applied | effectId, target |
BEFORE_STATUS_APPLY | Before status condition applied | statusId, target, canApply |
AFTER_SKIP_TURN | After skipping a turn | source |
AFTER_FAINT | After a Pokemon faints | target, source |
If an event isn't strongly typed, search for where it is emitted in BattlePokemon.js or Battle.js and add its type to battleEnums.js.
Condition Callbacks
Import from ../engine/eventConditions:
Common Condition Callbacks
| Callback | Description |
|---|---|
getIsTargetPokemonCallback(pokemon) | Only triggers when pokemon is the target |
getIsSourcePokemonCallback(pokemon) | Only triggers when pokemon is the source |
getIsActivePokemonCallback(pokemon) | Only triggers when pokemon is the active one |
getIsInstanceOfType("move") | Only triggers for move-related damage |
getIsTargetSameTeamCallback(pokemon) | Target is on same team |
getIsTargetOpponentCallback(pokemon) | Target is on opposing team |
getIsSourceSameTeamCallback(pokemon) | Source is on same team |
getIsNotSourcePokemonCallback(pokemon) | Source is NOT this pokemon |
getIsWeatherCondition(weatherId) | Current weather matches |
Composing Multiple Conditions
conditionCallback: composeConditionCallbacks(
getIsTargetPokemonCallback(target),
getIsInstanceOfType("move"),
),
Modifying Event Arguments
RECOMMENDED: Return an object from the callback to modify event behavior:
callback: (args) => {
return {
damage: Math.floor(args.damage * 0.5), // reduce damange by 50%
canAdd: false, // prevent something from being applied
};
};
Common Gotchas
- •
Always Unregister: Store listenerId and call
battle.unregisterListener(listenerId)in the remove function to prevent memory leaks. - •
Source vs Target: Use the correct condition callback:
- •
getIsSourcePokemonCallback- when this Pokemon is dealing damage/using moves - •
getIsTargetPokemonCallback- when this Pokemon is receiving damage/effects
- •
- •
Return vs Mutate: When modifying arguments, ALWAYS return the new value instead of mutating. Mutating is an old, deprecated pattern.
- •
Instance Check: Class-level
registerListenerFunctionautomatically checks if the component is still active before firing the callback.
References
- •
references/pattern-*.md- Common event listener implementation patterns