feat(spawner): add productivity need and inventory to spawned NPCs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-08 22:45:34 +00:00
parent 096597e7e5
commit 4670bfc08b
7 changed files with 27 additions and 5 deletions
+20 -1
View File
@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import { World } from '../../ecs/World.js';
import { GameMap } from '../../map/GameMap.js';
import { spawnNPC } from '../spawner.js';
import type { Position, Stats } from '@dflike/shared';
import type { Position, Stats, Needs } from '@dflike/shared';
describe('spawnNPC', () => {
it('spawns at random position when no hint given', () => {
@@ -49,6 +49,25 @@ describe('spawnNPC', () => {
expect(world.getComponent(entity, 'backstory')).toBe('');
});
it('spawned NPC has productivity need', () => {
const world = new World();
const map = new GameMap();
const entity = spawnNPC(world, map);
const needs = world.getComponent<Needs>(entity, 'needs')!;
expect(needs.productivity).toBeDefined();
expect(needs.productivity).toBeGreaterThanOrEqual(60);
});
it('spawned NPC has empty inventory', () => {
const world = new World();
const map = new GameMap();
const entity = spawnNPC(world, map);
const inventory = world.getComponent<Map<string, number>>(entity, 'inventory')!;
expect(inventory).toBeDefined();
expect(inventory).toBeInstanceOf(Map);
expect(inventory.size).toBe(0);
});
it('generates stats in 3-18 range', () => {
const world = new World();
const map = new GameMap();
+2
View File
@@ -16,6 +16,7 @@ export function spawnNPC(world: World, map: GameMap, positionHint?: Position, ev
world.addComponent<Needs>(entity, 'needs', {
hunger: 40 + Math.random() * 40, // 40-80
energy: 40 + Math.random() * 40,
productivity: 60 + Math.random() * 40, // 60-100
});
world.addComponent<Movement>(entity, 'movement', {
state: 'idle',
@@ -46,6 +47,7 @@ export function spawnNPC(world: World, map: GameMap, positionHint?: Position, ev
world.addComponent<StatModifiers>(entity, 'statModifiers', { modifiers: [] });
world.addComponent<Relationships>(entity, 'relationships', new Map());
world.addComponent<string>(entity, 'backstory', '');
world.addComponent<Map<string, number>>(entity, 'inventory', new Map());
eventMemoryService?.record(entity, {
type: 'spawned',
@@ -33,7 +33,7 @@ function createNPC(
): EntityId {
const e = world.createEntity();
world.addComponent<Position>(e, 'position', { x: 0, y: 0 });
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80 });
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80, productivity: 80 });
world.addComponent<Movement>(e, 'movement', {
state: 'idle', target: null, path: [], direction: 0, moveProgress: 0,
});
@@ -14,7 +14,7 @@ function createNPC(
): EntityId {
const e = world.createEntity();
world.addComponent<Position>(e, 'position', { x, y });
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80 });
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80, productivity: 80 });
world.addComponent<Movement>(e, 'movement', {
state: 'idle', target: null, path: [], direction: 0, moveProgress: 0,
});
@@ -22,6 +22,7 @@ function createNPC(
world.addComponent<Needs>(e, 'needs', {
hunger: opts?.hunger ?? 80,
energy: opts?.energy ?? 80,
productivity: 80,
});
world.addComponent<Movement>(e, 'movement', {
state: opts?.walking ? 'walking' : 'idle',
@@ -18,7 +18,7 @@ function setupEntity(
world.addComponent<Stats>(e, 'stats', base);
world.addComponent<StatModifiers>(e, 'statModifiers', { modifiers: [...modifiers] });
if (needs) {
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80, ...needs });
world.addComponent<Needs>(e, 'needs', { hunger: 80, energy: 80, productivity: 80, ...needs });
}
return e;
}
@@ -29,7 +29,7 @@ function makeNpc(world: World, name: string, needs?: Partial<Needs>): number {
world.addComponent(entity, 'name', name);
world.addComponent(entity, 'npcBrain', { currentGoal: 'wander' });
world.addComponent<Stats>(entity, 'stats', makeStats());
world.addComponent<Needs>(entity, 'needs', { hunger: 80, energy: 80, ...needs });
world.addComponent<Needs>(entity, 'needs', { hunger: 80, energy: 80, productivity: 80, ...needs });
return entity;
}