Add in throwable items (dagger) from pixel dungeon
This commit is contained in:
125
src/engine/gameplay/__tests__/CombatLogic.test.ts
Normal file
125
src/engine/gameplay/__tests__/CombatLogic.test.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { traceProjectile } from '../CombatLogic';
|
||||
import type { World } from '../../../core/types';
|
||||
import { EntityManager } from '../../EntityManager';
|
||||
import { TileType } from '../../../core/terrain';
|
||||
|
||||
describe('CombatLogic', () => {
|
||||
// Mock World
|
||||
const mockWorld: World = {
|
||||
width: 10,
|
||||
height: 10,
|
||||
tiles: new Array(100).fill(TileType.EMPTY),
|
||||
actors: new Map(),
|
||||
exit: { x: 9, y: 9 }
|
||||
};
|
||||
|
||||
// Helper to set wall
|
||||
const setWall = (x: number, y: number) => {
|
||||
mockWorld.tiles[y * mockWorld.width + x] = TileType.WALL;
|
||||
};
|
||||
|
||||
// Helper to clear world
|
||||
const clearWorld = () => {
|
||||
mockWorld.tiles.fill(TileType.EMPTY);
|
||||
mockWorld.actors.clear();
|
||||
};
|
||||
|
||||
// Mock EntityManager
|
||||
const mockEntityManager = {
|
||||
getActorsAt: (x: number, y: number) => {
|
||||
return [...mockWorld.actors.values()].filter(a => a.pos.x === x && a.pos.y === y);
|
||||
}
|
||||
} as unknown as EntityManager;
|
||||
|
||||
beforeEach(() => {
|
||||
clearWorld();
|
||||
});
|
||||
|
||||
describe('traceProjectile', () => {
|
||||
it('should travel full path if no obstacles', () => {
|
||||
const start = { x: 0, y: 0 };
|
||||
const end = { x: 5, y: 0 };
|
||||
|
||||
const result = traceProjectile(mockWorld, start, end, mockEntityManager);
|
||||
|
||||
expect(result.blockedPos).toEqual(end);
|
||||
expect(result.hitActorId).toBeUndefined();
|
||||
// Path should be (0,0) -> (1,0) -> (2,0) -> (3,0) -> (4,0) -> (5,0)
|
||||
// But raycast implementation includes start?
|
||||
// CombatLogic logic: "skip start" -> loop i=1
|
||||
// So result.path is full array from raycast.
|
||||
expect(result.path).toHaveLength(6);
|
||||
});
|
||||
|
||||
it('should stop at wall', () => {
|
||||
const start = { x: 0, y: 0 };
|
||||
const end = { x: 5, y: 0 };
|
||||
setWall(3, 0); // Wall at (3,0)
|
||||
|
||||
const result = traceProjectile(mockWorld, start, end, mockEntityManager);
|
||||
|
||||
expect(result.blockedPos).toEqual({ x: 3, y: 0 });
|
||||
expect(result.hitActorId).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should stop at enemy', () => {
|
||||
const start = { x: 0, y: 0 };
|
||||
const end = { x: 5, y: 0 };
|
||||
|
||||
// Place enemy at (3,0)
|
||||
const enemyId = 2;
|
||||
mockWorld.actors.set(enemyId, {
|
||||
id: enemyId,
|
||||
type: 'rat',
|
||||
category: 'combatant',
|
||||
pos: { x: 3, y: 0 },
|
||||
isPlayer: false
|
||||
// ... other props mocked if needed
|
||||
} as any);
|
||||
|
||||
const result = traceProjectile(mockWorld, start, end, mockEntityManager, 1); // Shooter 1
|
||||
|
||||
expect(result.blockedPos).toEqual({ x: 3, y: 0 });
|
||||
expect(result.hitActorId).toBe(enemyId);
|
||||
});
|
||||
|
||||
it('should ignore shooter position', () => {
|
||||
const start = { x: 0, y: 0 };
|
||||
const end = { x: 5, y: 0 };
|
||||
|
||||
// Shooter at start
|
||||
mockWorld.actors.set(1, {
|
||||
id: 1,
|
||||
type: 'player',
|
||||
category: 'combatant',
|
||||
pos: { x: 0, y: 0 },
|
||||
isPlayer: true
|
||||
} as any);
|
||||
|
||||
const result = traceProjectile(mockWorld, start, end, mockEntityManager, 1);
|
||||
|
||||
// Should not hit self
|
||||
expect(result.hitActorId).toBeUndefined();
|
||||
expect(result.blockedPos).toEqual(end);
|
||||
});
|
||||
|
||||
it('should ignore non-combatant actors (e.g. items)', () => {
|
||||
const start = { x: 0, y: 0 };
|
||||
const end = { x: 5, y: 0 };
|
||||
|
||||
// Item at (3,0)
|
||||
mockWorld.actors.set(99, {
|
||||
id: 99,
|
||||
category: 'item_drop',
|
||||
pos: { x: 3, y: 0 },
|
||||
} as any);
|
||||
|
||||
const result = traceProjectile(mockWorld, start, end, mockEntityManager);
|
||||
|
||||
// Should pass through item
|
||||
expect(result.blockedPos).toEqual(end);
|
||||
expect(result.hitActorId).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user