feat: wire stats into NPC spawner and game loop
Add stats and statModifiers components to spawnNPC, and run statModifierSystem as the first system in the GameLoop update cycle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { needsDecaySystem } from '../systems/needsDecaySystem.js';
|
||||
import { npcBrainSystem } from '../systems/npcBrainSystem.js';
|
||||
import { movementSystem } from '../systems/movementSystem.js';
|
||||
import { socialSystem } from '../systems/socialSystem.js';
|
||||
import { statModifierSystem } from '../systems/statModifierSystem.js';
|
||||
import { spawnNPC } from './spawner.js';
|
||||
|
||||
export class GameLoop {
|
||||
@@ -61,6 +62,7 @@ export class GameLoop {
|
||||
this.tick++;
|
||||
|
||||
// Run systems in order
|
||||
statModifierSystem(this.world);
|
||||
needsDecaySystem(this.world);
|
||||
npcBrainSystem(this.world, this.map);
|
||||
socialSystem(this.world);
|
||||
|
||||
@@ -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 } from '@dflike/shared';
|
||||
import type { Position, Stats } from '@dflike/shared';
|
||||
|
||||
describe('spawnNPC', () => {
|
||||
it('spawns at random position when no hint given', () => {
|
||||
@@ -44,5 +44,18 @@ describe('spawnNPC', () => {
|
||||
expect(world.getComponent(entity, 'appearance')).toBeDefined();
|
||||
expect(world.getComponent(entity, 'name')).toBeDefined();
|
||||
expect(world.getComponent(entity, 'socialState')).toBeDefined();
|
||||
expect(world.getComponent(entity, 'stats')).toBeDefined();
|
||||
expect(world.getComponent(entity, 'statModifiers')).toBeDefined();
|
||||
});
|
||||
|
||||
it('generates stats in 3-18 range', () => {
|
||||
const world = new World();
|
||||
const map = new GameMap();
|
||||
const entity = spawnNPC(world, map);
|
||||
const stats = world.getComponent<Stats>(entity, 'stats')!;
|
||||
for (const key of Object.keys(stats) as (keyof Stats)[]) {
|
||||
expect(stats[key]).toBeGreaterThanOrEqual(3);
|
||||
expect(stats[key]).toBeLessThanOrEqual(18);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,8 @@ import type { World } from '../ecs/World.js';
|
||||
import type { GameMap } from '../map/GameMap.js';
|
||||
import { generateRandomAppearance } from '../spawner/appearanceGenerator.js';
|
||||
import { generateName } from '../spawner/nameGenerator.js';
|
||||
import type { EntityId, Position, Needs, Movement, NPCBrain, Appearance, SocialState } from '@dflike/shared';
|
||||
import { generateStats } from '../spawner/statGenerator.js';
|
||||
import type { EntityId, Position, Needs, Movement, NPCBrain, Appearance, SocialState, Stats, StatModifiers } from '@dflike/shared';
|
||||
|
||||
export function spawnNPC(world: World, map: GameMap, positionHint?: Position): EntityId {
|
||||
const entity = world.createEntity();
|
||||
@@ -36,6 +37,8 @@ export function spawnNPC(world: World, map: GameMap, positionHint?: Position): E
|
||||
globalCooldown: 0,
|
||||
pairCooldowns: new Map(),
|
||||
});
|
||||
world.addComponent<Stats>(entity, 'stats', generateStats());
|
||||
world.addComponent<StatModifiers>(entity, 'statModifiers', { modifiers: [] });
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user