74 lines
2.6 KiB
JavaScript
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);
|
|
},
|
|
};
|