piclets / src /lib /battle-engine /remaining-triggers.test.ts
Fraser's picture
battle battle
e78d70c
import { describe, it, expect, beforeEach } from 'vitest';
import { BattleEngine } from './BattleEngine';
import type { PicletDefinition } from './types';
import { PicletType, AttackType } from './types';
describe('Remaining Trigger Events', () => {
let basicPiclet: PicletDefinition;
let triggerPiclet: PicletDefinition;
beforeEach(() => {
basicPiclet = {
name: "Basic Fighter",
description: "Standard test piclet",
tier: 'medium',
primaryType: PicletType.BEAST,
baseStats: { hp: 80, attack: 60, defense: 60, speed: 60 },
nature: "Hardy",
specialAbility: { name: "No Ability", description: "" },
movepool: [
{
name: "Basic Attack",
type: AttackType.BEAST,
power: 50,
accuracy: 100,
pp: 20,
priority: 0,
flags: ['contact'],
effects: [{ type: 'damage', target: 'opponent', amount: 'normal' }]
}
]
};
triggerPiclet = {
name: "Trigger Test",
description: "Tests all trigger events",
tier: 'medium',
primaryType: PicletType.CULTURE,
baseStats: { hp: 100, attack: 70, defense: 70, speed: 50 },
nature: "Bold",
specialAbility: {
name: "Multi Trigger",
description: "Triggers on various events",
triggers: []
},
movepool: [
{
name: "Drain Punch",
type: AttackType.BEAST,
power: 60,
accuracy: 100,
pp: 15,
priority: 0,
flags: ['contact'],
effects: [
{ type: 'damage', target: 'opponent', amount: 'normal', formula: 'drain', value: 0.5 }
]
},
{
name: "Status Move",
type: AttackType.CULTURE,
power: 0,
accuracy: 100,
pp: 20,
priority: 0,
flags: [],
effects: [
{ type: 'applyStatus', target: 'opponent', status: 'paralyze', chance: 100 }
]
},
{
name: "Stat Boost",
type: AttackType.CULTURE,
power: 0,
accuracy: 100,
pp: 20,
priority: 0,
flags: [],
effects: [
{ type: 'modifyStats', target: 'self', stats: { attack: 'increase' } }
]
},
{
name: "Heal Move",
type: AttackType.CULTURE,
power: 0,
accuracy: 100,
pp: 15,
priority: 0,
flags: [],
effects: [
{ type: 'heal', target: 'self', amount: 'large' }
]
}
]
};
});
describe('onStatusInflicted Trigger', () => {
it('should trigger when status effect is applied', () => {
const statusTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Status Aware",
description: "Triggers when status is inflicted",
triggers: [
{
event: 'onStatusInflicted',
condition: 'always',
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { attack: 'increase' }
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, statusTriggerPiclet);
const initialAttack = engine.getState().opponentPiclet.attack;
// Use status move to trigger the ability
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 1 } // Status Move
);
const finalAttack = engine.getState().opponentPiclet.attack;
const log = engine.getLog();
console.log('Status inflicted test log:', log);
console.log('Initial attack:', initialAttack, 'Final attack:', finalAttack);
expect(finalAttack).toBeGreaterThan(initialAttack);
expect(log.some(msg => msg.includes('Status Aware') && msg.includes('triggered'))).toBe(true);
});
});
describe('onHPDrained Trigger', () => {
it('should trigger when HP is drained from opponent', () => {
const drainTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Life Stealer",
description: "Triggers when draining HP",
triggers: [
{
event: 'onHPDrained',
condition: 'always',
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { speed: 'increase' }
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, drainTriggerPiclet);
const initialSpeed = engine.getState().opponentPiclet.speed;
// Use drain move to trigger the ability
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 } // Drain Punch
);
const finalSpeed = engine.getState().opponentPiclet.speed;
const log = engine.getLog();
expect(finalSpeed).toBeGreaterThan(initialSpeed);
expect(log.some(msg => msg.includes('Life Stealer') && msg.includes('triggered'))).toBe(true);
});
});
describe('beforeMoveUse/afterMoveUse Triggers', () => {
it('should trigger before and after move use', () => {
const moveTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Move Monitor",
description: "Triggers before and after moves",
triggers: [
{
event: 'beforeMoveUse',
condition: 'always',
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { defense: 'increase' }
}
]
},
{
event: 'afterMoveUse',
condition: 'always',
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { accuracy: 'increase' }
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, moveTriggerPiclet);
const initialDefense = engine.getState().opponentPiclet.defense;
const initialAccuracy = engine.getState().opponentPiclet.accuracy;
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const finalDefense = engine.getState().opponentPiclet.defense;
const finalAccuracy = engine.getState().opponentPiclet.accuracy;
const log = engine.getLog();
expect(finalDefense).toBeGreaterThan(initialDefense);
expect(finalAccuracy).toBeGreaterThan(initialAccuracy);
expect(log.some(msg => msg.includes('Move Monitor') && msg.includes('triggered'))).toBe(true);
});
});
describe('onFullHP Trigger', () => {
it('should trigger when HP reaches maximum', () => {
const fullHpTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Full Power",
description: "Triggers when at full HP",
triggers: [
{
event: 'onFullHP',
condition: 'always',
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { attack: 'greatly_increase' }
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, fullHpTriggerPiclet);
// Damage the piclet first
engine['state'].opponentPiclet.currentHp = Math.floor(engine['state'].opponentPiclet.maxHp * 0.5);
const initialAttack = engine.getState().opponentPiclet.attack;
// Use heal move to reach full HP
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 3 } // Heal Move
);
const finalAttack = engine.getState().opponentPiclet.attack;
const log = engine.getLog();
// Should trigger if healed to full HP
if (engine.getState().opponentPiclet.currentHp === engine.getState().opponentPiclet.maxHp) {
expect(finalAttack).toBeGreaterThan(initialAttack);
expect(log.some(msg => msg.includes('Full Power') && msg.includes('triggered'))).toBe(true);
}
});
});
describe('onOpponentContactMove Trigger', () => {
it('should trigger when opponent uses contact move', () => {
const contactTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Rough Skin",
description: "Triggers when hit by contact moves",
triggers: [
{
event: 'onOpponentContactMove',
condition: 'always',
effects: [
{
type: 'damage',
target: 'opponent',
amount: 'weak'
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, contactTriggerPiclet);
const initialPlayerHp = engine.getState().playerPiclet.currentHp;
// Player uses contact move
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 }, // Basic Attack (contact)
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const finalPlayerHp = engine.getState().playerPiclet.currentHp;
const log = engine.getLog();
// Player should take damage from contact
expect(finalPlayerHp).toBeLessThan(initialPlayerHp);
expect(log.some(msg => msg.includes('Rough Skin') && msg.includes('triggered'))).toBe(true);
});
});
describe('onStatChange Trigger', () => {
it('should trigger when stats are modified', () => {
const statTriggerPiclet = {
...triggerPiclet,
specialAbility: {
name: "Stat Monitor",
description: "Triggers when stats change",
triggers: [
{
event: 'onStatChange',
condition: 'always',
effects: [
{
type: 'heal',
target: 'self',
amount: 'small'
}
]
}
]
}
};
const engine = new BattleEngine(basicPiclet, statTriggerPiclet);
// Damage the piclet first so healing is visible
engine['state'].opponentPiclet.currentHp = Math.floor(engine['state'].opponentPiclet.maxHp * 0.8);
const initialHp = engine.getState().opponentPiclet.currentHp;
// Use stat boost move to trigger the ability
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 2 } // Stat Boost
);
const finalHp = engine.getState().opponentPiclet.currentHp;
const log = engine.getLog();
expect(finalHp).toBeGreaterThan(initialHp);
expect(log.some(msg => msg.includes('Stat Monitor') && msg.includes('triggered'))).toBe(true);
});
});
});