import { config } from '../config/Config.js'; /** * Deterministic name synthesis. Everything is drawn from the caller's * Rng (so names are part of the seed), with syllable pools coming from * data/naming.json. Code-level fallbacks keep this working even if the * file is missing. * * const rng = Rng.derive(seed, 'name', 'S000123'); * const name = NameGenerator.star(rng); // "Kethavoryn" */ const FALLBACK = { star: { syllables: ['ka', 'vel', 'thu', 'ori', 'an', 'esh', 'mar', 'dy', 'neth', 'avi', 'cor', 'lu', 'tan', 'ys', 'brei', 'hal', 'ion'], minParts: 2, maxParts: 4, }, planet: { roots: ['aurel', 'bryn', 'cald', 'dross', 'emrys', 'fen', 'gale', 'hyra', 'ilv', 'jor', 'kest', 'lun', 'mora', 'neth', 'orb', 'pyre', 'quill', 'ross', 'sable', 'tarn', 'ulric', 'vex', 'wren', 'xan', 'yrra', 'zeph'], }, galaxy: { syllables: ['an', 'dro', 'me', 'mil', 'ky', 'cen', 'tau', 'rhi', 'sa', 'vel', 'pyr', 'os'], minParts: 3, maxParts: 5, }, }; const ROMAN = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX']; function section(name, fallback) { const v = config.get(`naming.${name}`); return (v && typeof v === 'object') ? v : fallback; } function capitalize(s) { return s.length ? s.charAt(0).toUpperCase() + s.slice(1) : s; } function joinSyllables(rng, syllables, minParts, maxParts) { const parts = rng.int(minParts, maxParts); let out = ''; for (let i = 0; i < parts; i++) out += rng.pick(syllables) ?? 'a'; return capitalize(out); } /** "1" → "I" … "20" → "XX"; beyond that, plain digits. */ export function ordinalLabel(n) { return ROMAN[n - 1] ?? String(n); } export const NameGenerator = { /** A star / system name: "Kethavoryn". */ star(rng) { const s = section('star', FALLBACK.star); const syllables = Array.isArray(s.syllables) && s.syllables.length ? s.syllables : FALLBACK.star.syllables; return joinSyllables(rng, syllables, s.minParts ?? 2, s.maxParts ?? 4); }, /** A planet root word: "Aurel" (compose the ordinal yourself). */ planetRoot(rng) { const p = section('planet', FALLBACK.planet); const roots = Array.isArray(p.roots) && p.roots.length ? p.roots : FALLBACK.planet.roots; return capitalize(rng.pick(roots) ?? 'Novus'); }, /** A galaxy name: "Vethani". */ galaxy(rng) { const g = section('galaxy', FALLBACK.galaxy); const syllables = Array.isArray(g.syllables) && g.syllables.length ? g.syllables : FALLBACK.galaxy.syllables; return joinSyllables(rng, syllables, g.minParts ?? 3, g.maxParts ?? 5); }, };