Skip to main content
Glama
spatial-combat.test.ts6.37 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' }; /** * CRIT-003: Spatial Collision Not Enforced * * Tests for spatial positioning and movement collision in combat. * Movement should be blocked by obstacles and other combatants. */ describe('CRIT-003: Spatial Combat Movement', () => { beforeEach(() => { closeDb(); getDb(':memory:'); clearCombatState(); }); describe('Movement with Positions', () => { it('should support position data on participants', async () => { const result = await handleCreateEncounter({ seed: 'pos-test-1', participants: [ { id: 'hero-1', name: 'Hero', initiativeBonus: 2, hp: 30, maxHp: 30, position: { x: 0, y: 0 } }, { id: 'goblin-1', name: 'Goblin', initiativeBonus: 1, hp: 7, maxHp: 7, isEnemy: true, position: { x: 5, y: 0 } } ] }, mockCtx); const text = result.content[0].text; // Encounter created successfully with positions expect(text).toContain('hero-1'); expect(text).toContain('goblin-1'); }); it('should execute move action to new position', async () => { // Create encounter with positions const createResult = await handleCreateEncounter({ seed: 'move-test-1', participants: [ { id: 'hero-1', name: 'Hero', initiativeBonus: 5, hp: 30, maxHp: 30, position: { x: 0, y: 0 } }, { id: 'goblin-1', name: 'Goblin', initiativeBonus: 1, hp: 7, maxHp: 7, isEnemy: true, position: { x: 10, y: 0 } } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Execute move action const moveResult = await handleExecuteCombatAction({ encounterId, action: 'move', actorId: 'hero-1', targetPosition: { x: 3, y: 0 } }, mockCtx); const moveText = moveResult.content[0].text; expect(moveText).toContain('move'); // Position should be updated expect(moveText).toContain('3'); }); it('should block movement onto occupied squares', async () => { // Create encounter with goblin at a specific position const createResult = await handleCreateEncounter({ seed: 'block-test-1', participants: [ { id: 'hero-1', name: 'Hero', initiativeBonus: 5, hp: 30, maxHp: 30, position: { x: 0, y: 0 } }, { id: 'goblin-1', name: 'Goblin', initiativeBonus: 1, hp: 7, maxHp: 7, isEnemy: true, position: { x: 2, y: 0 } } ] }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Try to move ONTO the goblin's position - should be blocked const moveResult = await handleExecuteCombatAction({ encounterId, action: 'move', actorId: 'hero-1', targetPosition: { x: 2, y: 0 } // Same as goblin position }, mockCtx); const moveText = moveResult.content[0].text; // Should fail - destination is occupied expect(moveText).toMatch(/blocked|cannot/i); }); }); describe('Terrain Obstacles', () => { it('should block movement onto terrain obstacles', async () => { // Create encounter with terrain const createResult = await handleCreateEncounter({ seed: 'terrain-test-1', participants: [ { id: 'hero-1', name: 'Hero', initiativeBonus: 5, hp: 30, maxHp: 30, position: { x: 0, y: 0 } } ], terrain: { obstacles: ['2,0'] // Wall tile } }, mockCtx); const createData = JSON.parse(createResult.content[0].text.match(/<!-- STATE_JSON\n([\s\S]*?)\nSTATE_JSON -->/)?.[1] || '{}'); const encounterId = createData.encounterId; // Try to move ONTO the wall tile - should fail const moveResult = await handleExecuteCombatAction({ encounterId, action: 'move', actorId: 'hero-1', targetPosition: { x: 2, y: 0 } // The wall position }, mockCtx); const moveText = moveResult.content[0].text; // Should be blocked - destination is an obstacle expect(moveText).toMatch(/blocked|cannot/i); }); }); });

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