names
This commit is contained in:
parent
e1bb10ff8a
commit
4bf36b1f59
6 changed files with 157 additions and 43 deletions
|
|
@ -1,6 +1,13 @@
|
|||
import { MAP_H, MAP_W, indexOf, inside } from "./grid.js";
|
||||
import { hash2 } from "./random.js";
|
||||
|
||||
export const NAME_PROBABILITIES = {
|
||||
contextSuffix: 0.42,
|
||||
secondInfix: 0.22,
|
||||
prefixOnly: 0.38,
|
||||
customName: 1.0,
|
||||
};
|
||||
|
||||
const CONTEXT_SUFFIXES = {
|
||||
coastal: ["\u6d5c", "\u6e4a", "\u6e2f", "\u6d66", "\u6d25", "\u5d0e", "\u6e7e"],
|
||||
river: ["\u5ddd", "\u702c", "\u6a4b", "\u6e21", "\u6cbc", "\u6ca2"],
|
||||
|
|
@ -22,38 +29,79 @@ function isNearSea(x, y, sea, radius = 3) {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function chooseNameSuffixPool(entity, fields) {
|
||||
function boundedIndex(entity) {
|
||||
return indexOf(Math.max(0, Math.min(MAP_W - 1, entity.x)), Math.max(0, Math.min(MAP_H - 1, entity.y)));
|
||||
}
|
||||
|
||||
function chooseNameContext(entity, fields) {
|
||||
const kind = String(entity.kind || "").toLowerCase();
|
||||
const i = indexOf(Math.max(0, Math.min(MAP_W - 1, entity.x)), Math.max(0, Math.min(MAP_H - 1, entity.y)));
|
||||
const i = boundedIndex(entity);
|
||||
const coastal = (fields?.coastalLowland?.[i] || 0) > 0.35 || isNearSea(entity.x, entity.y, fields?.sea);
|
||||
const river = (fields?.river?.[i] || 0) > 0.35 || (fields?.valleyField?.[i] || 0) > 0.42;
|
||||
const plain = (fields?.plain?.[i] || 0) > 0.48 || (fields?.agriculture?.[i] || 0) > 0.46 || (fields?.basinField?.[i] || 0) > 0.35;
|
||||
const mountain = (fields?.elevation?.[i] || 0) > 0.52 || (fields?.slope?.[i] || 0) > 0.35 || (fields?.ridgeField?.[i] || 0) > 0.42;
|
||||
|
||||
if (kind.includes("port") || kind.includes("harbor") || entity.portClass) return CONTEXT_SUFFIXES.coastal;
|
||||
if (kind.includes("crossing") || kind.includes("bridge")) return CONTEXT_SUFFIXES.river;
|
||||
if (kind.includes("pass") || kind.includes("mountain")) return CONTEXT_SUFFIXES.mountain;
|
||||
if (kind.includes("castle") || kind.includes("market")) return CONTEXT_SUFFIXES.historic;
|
||||
if (kind.includes("new town") || kind.includes("satellite")) return CONTEXT_SUFFIXES.suburban;
|
||||
if (coastal && !mountain) return CONTEXT_SUFFIXES.coastal;
|
||||
if (river) return CONTEXT_SUFFIXES.river;
|
||||
if (mountain && !plain) return CONTEXT_SUFFIXES.mountain;
|
||||
if (plain) return CONTEXT_SUFFIXES.plain;
|
||||
return CONTEXT_SUFFIXES.plain;
|
||||
if (kind.includes("port") || kind.includes("harbor") || entity.portClass) return "coastal";
|
||||
if (kind.includes("crossing") || kind.includes("bridge")) return "river";
|
||||
if (kind.includes("pass") || kind.includes("mountain")) return "mountain";
|
||||
if (kind.includes("castle") || kind.includes("market")) return "historic";
|
||||
if (kind.includes("new town") || kind.includes("satellite")) return "suburban";
|
||||
if (coastal && !mountain) return "coastal";
|
||||
if (river) return "river";
|
||||
if (mountain && !plain) return "mountain";
|
||||
if (plain) return "plain";
|
||||
return "plain";
|
||||
}
|
||||
|
||||
export function chooseNameSuffixPool(entity, fields) {
|
||||
return CONTEXT_SUFFIXES[chooseNameContext(entity, fields)] || CONTEXT_SUFFIXES.plain;
|
||||
}
|
||||
|
||||
function chooseContextFreePool(entity, fields, nameParts) {
|
||||
const context = chooseNameContext(entity, fields);
|
||||
return nameParts.contextFree?.[context] || nameParts.contextFree?.plain || nameParts.infixes || nameParts.free || [""];
|
||||
}
|
||||
|
||||
function pick(pool, seed, n, salt) {
|
||||
if (!pool?.length) return "";
|
||||
const index = Math.floor(hash2(n + salt * 101, seed + salt * 1009, seed + n * 37 + salt) * pool.length) % pool.length;
|
||||
return pool[index];
|
||||
}
|
||||
|
||||
function chance(seed, n, salt, probability) {
|
||||
return hash2(n + salt * 173, seed + salt * 811, seed + n * 43 + salt) < probability;
|
||||
}
|
||||
|
||||
function appendPart(parts, part) {
|
||||
if (!part) return;
|
||||
const previous = parts[parts.length - 1] || "";
|
||||
if (previous && (previous === part || previous.endsWith(part) || part.startsWith(previous))) return;
|
||||
parts.push(part);
|
||||
}
|
||||
|
||||
export function contextualDefaultName(seed, id, entity, nameParts, fields, attempt = 0) {
|
||||
const prefixKey = id.split("-")[0];
|
||||
const n = Number(id.split("-")[1] || 0) + attempt * 997;
|
||||
const prefixes = nameParts.prefixes || [""];
|
||||
const infixes = nameParts.infixes || [""];
|
||||
const suffixPool = chooseNameSuffixPool(entity, fields);
|
||||
const fallbackSuffixes = nameParts.suffixes || [""];
|
||||
const prefix = prefixes[(seed + n * 7) % prefixes.length];
|
||||
const useInfix = hash2(n + prefixKey.length * 17, seed + n * 31, seed + 2777) >= 0.78;
|
||||
const infix = useInfix ? infixes[(seed * 3 + n * 11) % infixes.length] : "";
|
||||
const contextualSuffix = suffixPool[(seed * 5 + n * 13 + prefixKey.length) % suffixPool.length];
|
||||
const fallbackSuffix = fallbackSuffixes[(seed * 7 + n * 17 + prefixKey.length) % fallbackSuffixes.length];
|
||||
const suffix = attempt % 4 === 3 ? fallbackSuffix : contextualSuffix;
|
||||
return `${prefix}${infix}${suffix}`;
|
||||
const infixes = nameParts.infixes || nameParts.free || [""];
|
||||
const suffixes = nameParts.suffixes || [""];
|
||||
const contextFree = chooseContextFreePool(entity, fields, nameParts);
|
||||
const contextSuffixes = chooseNameSuffixPool(entity, fields);
|
||||
const parts = [];
|
||||
|
||||
if (chance(seed, n, 11 + prefixKey.length, NAME_PROBABILITIES.prefixOnly)) {
|
||||
appendPart(parts, pick(prefixes, seed, n, 101));
|
||||
}
|
||||
|
||||
const useContextMain = chance(seed, n, 13 + prefixKey.length, 0.42);
|
||||
appendPart(parts, pick(useContextMain ? contextFree : infixes, seed, n, useContextMain ? 211 : 223));
|
||||
|
||||
if (chance(seed, n, 19 + prefixKey.length, NAME_PROBABILITIES.secondInfix)) {
|
||||
appendPart(parts, pick(infixes, seed, n, 401));
|
||||
}
|
||||
|
||||
const useContextSuffix = chance(seed, n, 23 + prefixKey.length, NAME_PROBABILITIES.contextSuffix);
|
||||
appendPart(parts, pick(useContextSuffix ? contextSuffixes : suffixes, seed, n, useContextSuffix ? 503 : 509));
|
||||
|
||||
return parts.slice(-3).join("") || pick(suffixes, seed, n, 601) || "\u539f";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue