piclets / src /lib /battle-engine /advanced-mechanic-overrides.test.ts
Fraser's picture
pre ide
7b95878
import { describe, it, expect, beforeEach } from 'vitest';
import { BattleEngine } from './BattleEngine';
import type { PicletDefinition, SpecialAbility } from './types';
import { PicletType, AttackType } from './types';
describe('Advanced Mechanic Override System', () => {
describe('Critical Hit Mechanics', () => {
it('should prevent critical hits with Shell Armor ability', () => {
const shellArmor: SpecialAbility = {
name: "Shell Armor",
description: "Hard shell prevents critical hits",
effects: [
{
type: 'mechanicOverride',
mechanic: 'criticalHits',
condition: 'always',
value: false
}
]
};
const defender: PicletDefinition = {
name: "Shell Defender",
description: "Protected by hard shell",
tier: 'medium',
primaryType: PicletType.MINERAL,
baseStats: { hp: 80, attack: 60, defense: 80, speed: 40 },
nature: "Impish",
specialAbility: shellArmor,
movepool: [
{
name: "Defense Curl",
type: AttackType.NORMAL,
power: 0,
accuracy: 100,
pp: 10,
priority: 0,
flags: [],
effects: [
{
type: 'modifyStats',
target: 'self',
stats: { defense: 'increase' }
}
]
}
]
};
const attacker: PicletDefinition = {
name: "High Crit Attacker",
description: "Has high critical hit rate",
tier: 'medium',
primaryType: PicletType.BEAST,
baseStats: { hp: 70, attack: 90, defense: 50, speed: 80 },
nature: "Adamant",
specialAbility: { name: "No Ability", description: "" },
movepool: [
{
name: "Slash",
type: AttackType.BEAST,
power: 70,
accuracy: 100,
pp: 10,
priority: 0,
flags: ['contact'],
effects: [
{
type: 'damage',
target: 'opponent',
amount: 'normal'
}
]
}
]
};
const engine = new BattleEngine(defender, attacker);
// Force high crit rate for testing
const originalCritRate = (engine as any).calculateCriticalChance;
(engine as any).calculateCriticalChance = () => 1.0; // 100% crit rate normally
let criticalHitOccurred = false;
for (let i = 0; i < 10; i++) {
const initialHp = engine.getState().playerPiclet.currentHp;
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const log = engine.getLog();
if (log.some(msg => msg.includes('critical') || msg.includes('Critical'))) {
criticalHitOccurred = true;
break;
}
if (engine.isGameOver()) break;
}
// Shell Armor should prevent ALL critical hits
expect(criticalHitOccurred).toBe(false);
// Restore original function
(engine as any).calculateCriticalChance = originalCritRate;
});
it('should guarantee critical hits with certain abilities', () => {
const alwaysCrit: SpecialAbility = {
name: "Super Luck",
description: "Always lands critical hits",
effects: [
{
type: 'mechanicOverride',
mechanic: 'criticalHits',
condition: 'always',
value: true
}
]
};
const critUser: PicletDefinition = {
name: "Lucky Fighter",
description: "Always gets critical hits",
tier: 'medium',
primaryType: PicletType.BEAST,
baseStats: { hp: 70, attack: 80, defense: 60, speed: 90 },
nature: "Hasty",
specialAbility: alwaysCrit,
movepool: [
{
name: "Strike",
type: AttackType.BEAST,
power: 60,
accuracy: 100,
pp: 10,
priority: 0,
flags: ['contact'],
effects: [
{
type: 'damage',
target: 'opponent',
amount: 'normal'
}
]
}
]
};
const opponent: PicletDefinition = {
name: "Opponent",
description: "Standard opponent",
tier: 'medium',
primaryType: PicletType.BEAST,
baseStats: { hp: 80, attack: 60, defense: 60, speed: 70 },
nature: "Hardy",
specialAbility: { name: "No Ability", description: "" },
movepool: [
{
name: "Tackle",
type: AttackType.NORMAL,
power: 40,
accuracy: 100,
pp: 10,
priority: 0,
flags: ['contact'],
effects: [{ type: 'damage', target: 'opponent', amount: 'normal' }]
}
]
};
const engine = new BattleEngine(critUser, opponent);
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const log = engine.getLog();
expect(log.some(msg => msg.includes('critical') || msg.includes('Critical'))).toBe(true);
});
});
describe('Status Immunity', () => {
it('should provide immunity to specific status effects', () => {
const insomnia: SpecialAbility = {
name: "Insomnia",
description: "Prevents sleep status",
effects: [
{
type: 'mechanicOverride',
mechanic: 'statusImmunity',
value: ['sleep']
}
]
};
const insomniac: PicletDefinition = {
name: "Sleepless Fighter",
description: "Cannot be put to sleep",
tier: 'medium',
primaryType: PicletType.CULTURE,
baseStats: { hp: 70, attack: 60, defense: 60, speed: 80 },
nature: "Timid",
specialAbility: insomnia,
movepool: [
{
name: "Tackle",
type: AttackType.NORMAL,
power: 40,
accuracy: 100,
pp: 10,
priority: 0,
flags: ['contact'],
effects: [{ type: 'damage', target: 'opponent', amount: 'normal' }]
}
]
};
const sleepUser: PicletDefinition = {
name: "Sleep Inducer",
description: "Puts opponents to sleep",
tier: 'medium',
primaryType: PicletType.CULTURE,
baseStats: { hp: 80, attack: 50, defense: 70, speed: 60 },
nature: "Calm",
specialAbility: { name: "No Ability", description: "" },
movepool: [
{
name: "Sleep Powder",
type: AttackType.FLORA,
power: 0,
accuracy: 75,
pp: 10,
priority: 0,
flags: [],
effects: [
{
type: 'applyStatus',
target: 'opponent',
status: 'sleep'
}
]
}
]
};
const engine = new BattleEngine(insomniac, sleepUser);
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const log = engine.getLog();
expect(log.some(msg => msg.includes('immune') || msg.includes('had no effect'))).toBe(true);
expect(log.some(msg => msg.includes('fell asleep'))).toBe(false);
});
});
describe('Type Immunity', () => {
it('should provide immunity to specific attack types', () => {
const levitate: SpecialAbility = {
name: "Levitate",
description: "Floating ability makes ground moves miss",
effects: [
{
type: 'mechanicOverride',
mechanic: 'typeImmunity',
value: ['ground']
}
]
};
const levitator: PicletDefinition = {
name: "Floating Fighter",
description: "Levitates above ground attacks",
tier: 'medium',
primaryType: PicletType.SPACE,
baseStats: { hp: 75, attack: 70, defense: 60, speed: 85 },
nature: "Timid",
specialAbility: levitate,
movepool: [
{
name: "Air Slash",
type: AttackType.SPACE,
power: 60,
accuracy: 95,
pp: 10,
priority: 0,
flags: [],
effects: [
{
type: 'damage',
target: 'opponent',
amount: 'normal'
}
]
}
]
};
const groundUser: PicletDefinition = {
name: "Ground Attacker",
description: "Uses ground-based attacks",
tier: 'medium',
primaryType: PicletType.MINERAL,
baseStats: { hp: 80, attack: 80, defense: 70, speed: 60 },
nature: "Adamant",
specialAbility: { name: "No Ability", description: "" },
movepool: [
{
name: "Earthquake",
type: AttackType.MINERAL,
power: 100,
accuracy: 100,
pp: 10,
priority: 0,
flags: ['ground'],
effects: [
{
type: 'damage',
target: 'opponent',
amount: 'strong'
}
]
}
]
};
const engine = new BattleEngine(levitator, groundUser);
const initialHp = engine.getState().playerPiclet.currentHp;
engine.executeActions(
{ type: 'move', piclet: 'player', moveIndex: 0 },
{ type: 'move', piclet: 'opponent', moveIndex: 0 }
);
const finalHp = engine.getState().playerPiclet.currentHp;
const log = engine.getLog();
// Ground move should have no effect due to Levitate
expect(finalHp).toBe(initialHp);
expect(log.some(msg => msg.includes('had no effect') || msg.includes('immune'))).toBe(true);
});
});
});