feat: add NPC name generator and broadcast names in entity state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-03-07 04:33:42 +00:00
parent d46677389f
commit 0cf48ded61
5 changed files with 42 additions and 0 deletions
+2
View File
@@ -1,6 +1,7 @@
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 } from '@dflike/shared';
export function spawnNPC(world: World, map: GameMap): EntityId {
@@ -24,6 +25,7 @@ export function spawnNPC(world: World, map: GameMap): EntityId {
goalQueue: [],
});
world.addComponent<Appearance>(entity, 'appearance', generateRandomAppearance());
world.addComponent<string>(entity, 'name', generateName());
return entity;
}
+1
View File
@@ -15,6 +15,7 @@ export function serializeEntity(world: World, entityId: number): EntityState {
needs: world.getComponent<Needs>(entityId, 'needs'),
npcBrain: world.getComponent<NPCBrain>(entityId, 'npcBrain'),
playerControlled: world.getComponent<PlayerControlled>(entityId, 'playerControlled'),
name: world.getComponent<string>(entityId, 'name'),
};
}
@@ -0,0 +1,19 @@
import { describe, it, expect } from 'vitest';
import { generateName } from '../nameGenerator.js';
describe('generateName', () => {
it('returns a non-empty string', () => {
const name = generateName();
expect(name).toBeTruthy();
expect(typeof name).toBe('string');
expect(name.length).toBeGreaterThan(0);
});
it('generates varied names over many calls', () => {
const names = new Set<string>();
for (let i = 0; i < 30; i++) {
names.add(generateName());
}
expect(names.size).toBeGreaterThan(5);
});
});
+19
View File
@@ -0,0 +1,19 @@
const PREFIXES = [
'Urist', 'Kor', 'Bel', 'Thar', 'Grim', 'Hed', 'Mog', 'Zan',
'Dur', 'Fal', 'Nor', 'Vim', 'Erd', 'Sig', 'Bor', 'Tul',
'Arn', 'Hild', 'Dag', 'Sven', 'Brun', 'Kel', 'Ral', 'Tor',
];
const SUFFIXES = [
'mund', 'rik', 'mir', 'gard', 'sten', 'vald', 'dak', 'fen',
'grim', 'lok', 'nar', 'thas', 'borg', 'din', 'run', 'vik',
'gar', 'horn', 'mar', 'wulf', 'ban', 'dor', 'kel', 'ton',
];
function pick<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}
export function generateName(): string {
return pick(PREFIXES) + pick(SUFFIXES);
}
+1
View File
@@ -55,6 +55,7 @@ export interface EntityState {
needs?: Needs;
npcBrain?: NPCBrain;
playerControlled?: PlayerControlled;
name?: string; // NPC display name
}
export interface WorldState {