orbit/js/utils/NameGenerator.js

74 lines
2.6 KiB
JavaScript

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);
},
};