Skip to main content
Glama
damage-resistance.test.ts7.75 kB
import { describe, it, expect, beforeEach } from 'vitest'; import { handleCreateEncounter, handleExecuteCombatAction, clearCombatState } from '../../src/server/combat-tools.js'; import { closeDb, getDb } from '../../src/storage/index.js'; const mockCtx = { sessionId: 'test-session' }; /** * HIGH-002: Damage Resistance Not Applied * * Tests for damage resistance and vulnerability in combat. * - Resistance should halve damage * - Vulnerability should double damage * - Immunity should reduce damage to 0 */ describe('HIGH-002: Damage Resistance', () => { beforeEach(() => { closeDb(); getDb(':memory:'); clearCombatState(); }); describe('Damage Type and Resistance', () => { it('should halve fire damage for fire-resistant character', async () => { // Create encounter with fire-resistant hero const createResult = await handleCreateEncounter({ seed: 'resist-test-1', participants: [ { id: 'hero-1', name: 'Fire-Resistant Hero', initiativeBonus: 10, hp: 50, maxHp: 50, resistances: ['fire'] }, { id: 'dragon-1', name: 'Fire Dragon', initiativeBonus: 1, hp: 100, maxHp: 100, isEnemy: true } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Dragon attacks with fire breath (40 fire damage) const attackResult = await handleExecuteCombatAction({ encounterId, action: 'attack', actorId: 'dragon-1', targetId: 'hero-1', attackBonus: 10, dc: 10, // Guaranteed hit damage: 40, damageType: 'fire' }, mockCtx); const attackText = attackResult.content[0].text; // Should show resistance applied, damage halved to 20 expect(attackText).toMatch(/resist/i); expect(attackText).toContain('20'); // Halved damage }); it('should double damage for vulnerable character', async () => { // Create encounter with cold-vulnerable creature const createResult = await handleCreateEncounter({ seed: 'vuln-test-1', participants: [ { id: 'hero-1', name: 'Ice Mage', initiativeBonus: 10, hp: 30, maxHp: 30 }, { id: 'fire-elem-1', name: 'Fire Elemental', initiativeBonus: 1, hp: 50, maxHp: 50, isEnemy: true, vulnerabilities: ['cold'] } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Ice Mage attacks with cold damage (10 cold damage) const attackResult = await handleExecuteCombatAction({ encounterId, action: 'attack', actorId: 'hero-1', targetId: 'fire-elem-1', attackBonus: 10, dc: 10, // Guaranteed hit damage: 10, damageType: 'cold' }, mockCtx); const attackText = attackResult.content[0].text; // Should show vulnerability applied, damage doubled to 20 expect(attackText).toMatch(/vulnerab/i); expect(attackText).toContain('20'); // Doubled damage }); it('should apply immunity (0 damage) for immune character', async () => { // Create encounter with fire-immune creature const createResult = await handleCreateEncounter({ seed: 'immune-test-1', participants: [ { id: 'hero-1', name: 'Pyromancer', initiativeBonus: 10, hp: 30, maxHp: 30 }, { id: 'fire-elem-1', name: 'Fire Elemental', initiativeBonus: 1, hp: 50, maxHp: 50, isEnemy: true, immunities: ['fire'] } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Pyromancer attacks with fire damage const attackResult = await handleExecuteCombatAction({ encounterId, action: 'attack', actorId: 'hero-1', targetId: 'fire-elem-1', attackBonus: 10, dc: 10, damage: 30, damageType: 'fire' }, mockCtx); const attackText = attackResult.content[0].text; // Should show immunity, 0 damage expect(attackText).toMatch(/immun/i); }); it('should apply normal damage without damage type', async () => { // Create encounter - normal attack without type const createResult = await handleCreateEncounter({ seed: 'normal-test-1', participants: [ { id: 'hero-1', name: 'Fighter', initiativeBonus: 10, hp: 30, maxHp: 30 }, { id: 'goblin-1', name: 'Goblin', initiativeBonus: 1, hp: 20, maxHp: 20, isEnemy: true, resistances: ['fire'] // Has resistance but attack is slashing } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Normal attack (no type = physical/slashing) const attackResult = await handleExecuteCombatAction({ encounterId, action: 'attack', actorId: 'hero-1', targetId: 'goblin-1', attackBonus: 10, dc: 10, damage: 10 // No damageType - should be unaffected by fire resistance }, mockCtx); const attackText = attackResult.content[0].text; // Should NOT show resistance (different damage type) expect(attackText).not.toMatch(/resist/i); expect(attackText).toContain('10'); // Full damage }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mnehmos/rpg-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server