|
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; |
|
|
|
|
|
engine.executeActions( |
|
{ type: 'move', piclet: 'player', moveIndex: 0 }, |
|
{ type: 'move', piclet: 'opponent', moveIndex: 1 } |
|
); |
|
|
|
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; |
|
|
|
|
|
engine.executeActions( |
|
{ type: 'move', piclet: 'player', moveIndex: 0 }, |
|
{ type: 'move', piclet: 'opponent', moveIndex: 0 } |
|
); |
|
|
|
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); |
|
|
|
|
|
engine['state'].opponentPiclet.currentHp = Math.floor(engine['state'].opponentPiclet.maxHp * 0.5); |
|
const initialAttack = engine.getState().opponentPiclet.attack; |
|
|
|
|
|
engine.executeActions( |
|
{ type: 'move', piclet: 'player', moveIndex: 0 }, |
|
{ type: 'move', piclet: 'opponent', moveIndex: 3 } |
|
); |
|
|
|
const finalAttack = engine.getState().opponentPiclet.attack; |
|
const log = engine.getLog(); |
|
|
|
|
|
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; |
|
|
|
|
|
engine.executeActions( |
|
{ type: 'move', piclet: 'player', moveIndex: 0 }, |
|
{ type: 'move', piclet: 'opponent', moveIndex: 0 } |
|
); |
|
|
|
const finalPlayerHp = engine.getState().playerPiclet.currentHp; |
|
const log = engine.getLog(); |
|
|
|
|
|
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); |
|
|
|
|
|
engine['state'].opponentPiclet.currentHp = Math.floor(engine['state'].opponentPiclet.maxHp * 0.8); |
|
const initialHp = engine.getState().opponentPiclet.currentHp; |
|
|
|
|
|
engine.executeActions( |
|
{ type: 'move', piclet: 'player', moveIndex: 0 }, |
|
{ type: 'move', piclet: 'opponent', moveIndex: 2 } |
|
); |
|
|
|
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); |
|
}); |
|
}); |
|
}); |