SKILL.md
Adding Effects to Pokestar
Quick Reference
Files to modify:
src/enums/battleEnums.js- AddeffectIdEnum.YOUR_EFFECTentry (ONLY if not exists)src/battle/data/effects.js- Add the effect implementation
DO NOT modify other effects or battleConfig.js unless explicitly asked.
Effect Structure
[effectIdEnum.EFFECT_NAME]: new Effect({
id: effectIdEnum.EFFECT_NAME,
name: "Effect Name",
description: "Description of the effect",
type: effectTypes.BUFF, // BUFF, DEBUFF, or NEUTRAL
dispellable: true, // Can it be removed by dispell effects?
effectAdd({ battle, target, source, initialArgs }) {
// Called when effect is applied
// initialArgs contains arguments passed when applying the effect
return {
// Properties to store for later use in effectRemove
};
},
effectRemove({ battle, target, source, properties, initialArgs }) {
// Called when effect expires or is removed
// properties contains what effectAdd returned
// Clean up any listeners or state here
},
tags: [], // Optional: ["hazard", "test"]
}),
Properties Pattern
The most important pattern is the properties pattern - return state from effectAdd that you'll need in effectRemove:
effectAdd({ battle, target, source, initialArgs }) {
return {
listenerId: battle.registerListenerFunction({...}),
originalValue: target.getStat("atk"),
counter: 0,
};
},
effectRemove({ battle, target, properties }) {
battle.unregisterListener(properties.listenerId);
}
Event Listener Registration
Use battle.registerListenerFunction for effects (effects don't have a class-level helper):
effectAdd({ battle, target }) {
return {
listenerId: battle.registerListenerFunction({
eventName: battleEventEnum.BEFORE_DAMAGE,
callback: (args) => {
// Modify damage or perform logic
return { damage: Math.floor(args.damage * 0.5) };
},
conditionCallback: getIsTargetPokemonCallback(target),
}),
};
},
effectRemove({ battle, properties }) {
battle.unregisterListener(properties.listenerId);
}
Effect Types
| Type | Description |
|---|---|
effectTypes.BUFF |
Positive effect, can be dispelled by debuff-removing abilities |
effectTypes.DEBUFF |
Negative effect, can be dispelled by buff-removing abilities |
effectTypes.NEUTRAL |
Neither buff nor debuff, special handling |
Using initialArgs
Effects can receive arguments when applied. Access them in both add and remove:
effectAdd({ battle, target, initialArgs }) {
const { shield } = initialArgs;
battle.addToLog(`${target.name} is shielded for ${shield} damage!`);
return { shieldAmount: shield };
},
effectRemove({ battle, target, initialArgs }) {
const { shield } = initialArgs;
// initialArgs persists through the effect's lifetime
}
Common Gotchas
- Always Clean Up Listeners: Failing to unregister listeners causes memory leaks and incorrect behavior.
- Event Argument Modification: Return modified values from callbacks to change event behavior:
``javascript callback: (args) => { return { damage: Math.floor(args.damage * 0.5) }; }; ``
- State Management: Properties can be mutated during runtime - be careful with shared references.
- Dispellable Flag: Set
dispellable: falsefor effects that should persist through dispell abilities.
Validation
After implementing an effect, run the effect test suite to validate the implementation:
npm test -- src/battle/data/__tests__/effects.test.js
This runs an e2e test that verifies all effects can be applied and removed without throwing errors. If your new effect causes a test failure, fix the implementation and re-run until tests pass.
See the unit-test skill for more details on testing.
References
references/pattern-*.md- Common effect implementation patternsadd-event-listenerskill - Common event types and condition callbacks