feat: implement NPC systems (needs decay, brain, movement)

Add three ECS systems for NPC simulation:
- needsDecaySystem: decrements hunger/energy each tick, clamped at 0
- npcBrainSystem: goal selection based on need thresholds with pathfinding
- movementSystem: advances entities along computed paths

Includes 8 passing tests covering decay, goal prioritization, and movement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 18:19:07 -05:00
parent 30ea2f42c2
commit 83660609fc
4 changed files with 229 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
import { Direction, type Movement, type Position } from '@dflike/shared';
import type { World } from '../ecs/World.js';
function directionFromDelta(dx: number, dy: number): number {
if (Math.abs(dx) > Math.abs(dy)) return dx > 0 ? Direction.RIGHT : Direction.LEFT;
return dy > 0 ? Direction.DOWN : Direction.UP;
}
export function movementSystem(world: World): void {
for (const entity of world.query('position', 'movement')) {
const movement = world.getComponent<Movement>(entity, 'movement')!;
const pos = world.getComponent<Position>(entity, 'position')!;
if (movement.state !== 'walking' || movement.path.length === 0) {
if (movement.state === 'walking' && movement.path.length === 0) {
movement.state = 'idle';
movement.target = null;
}
continue;
}
const next = movement.path.shift()!;
movement.direction = directionFromDelta(next.x - pos.x, next.y - pos.y);
pos.x = next.x;
pos.y = next.y;
if (movement.path.length === 0) {
movement.state = 'idle';
movement.target = null;
}
}
}