Fantasy-Map-Generator/src/scripts/generation/pack/burgsAndStates/generateBurgsAndStates.ts
2022-09-03 19:52:22 +03:00

131 lines
3.5 KiB
TypeScript

import {WARN} from "config/logging";
import {pick} from "utils/functionUtils";
import {getInputNumber} from "utils/nodeUtils";
import {collectStatistics} from "./collectStatistics";
import {NEUTRALS, NO_BURG} from "./config";
import {createCapitals} from "./createCapitals";
import {createStateData} from "./createStateData";
import {createTowns} from "./createTowns";
import {expandStates} from "./expandStates";
import {specifyBurgs} from "./specifyBurgs";
import {specifyStates} from "./specifyStates";
type TCellsData = Pick<
IPack["cells"],
| "v"
| "c"
| "p"
| "b"
| "i"
| "g"
| "area"
| "h"
| "f"
| "t"
| "haven"
| "harbor"
| "r"
| "fl"
| "biome"
| "s"
| "pop"
| "culture"
>;
export function generateBurgsAndStates(
cultures: TCultures,
features: TPackFeatures,
temp: Int8Array,
rivers: Omit<IRiver, "name" | "basin" | "type">[],
vertices: IGraphVertices,
cells: TCellsData
): {burgIds: Uint16Array; stateIds: Uint16Array; burgs: TBurgs; states: TStates} {
const cellsNumber = cells.i.length;
const scoredCellIds = getScoredCellIds();
const statesNumber = getStatesNumber(scoredCellIds.length);
if (statesNumber === 0) {
return {
burgIds: new Uint16Array(cellsNumber),
stateIds: new Uint16Array(cellsNumber),
burgs: [NO_BURG],
states: [NEUTRALS]
};
}
const capitals = createCapitals(statesNumber, scoredCellIds, cultures, pick(cells, "p", "f", "culture"));
const capitalCells = new Map(capitals.map(({cell}) => [cell, true]));
const statesData = createStateData(capitals, cultures);
const towns = createTowns(
cultures,
scoredCellIds.filter(i => !capitalCells.has(i)),
pick(cells, "p", "i", "f", "s", "culture")
);
const stateIds = expandStates(
capitalCells,
statesData,
features,
pick(cells, "c", "h", "f", "t", "r", "fl", "s", "biome", "culture")
);
const burgs = specifyBurgs(
capitals,
towns,
stateIds,
features,
temp,
vertices,
cultures,
statesData,
rivers,
pick(cells, "v", "p", "g", "h", "f", "haven", "harbor", "s", "biome", "fl", "r")
);
const burgIds = assignBurgIds(burgs);
const statistics = collectStatistics({...cells, state: stateIds, burg: burgIds}, burgs);
const states = specifyStates(statesData, statistics, cultures, burgs);
return {burgIds, stateIds, burgs, states};
function getScoredCellIds() {
const score = new Int16Array(cells.s.map(s => s * Math.random()));
// filtered and sorted array of indexes: only populated cells not on map edge
const sorted = cells.i
.filter(i => !cells.b[i] && score[i] > 0 && cells.culture[i])
.sort((a, b) => score[b] - score[a]);
return sorted;
}
function getStatesNumber(populatedCells: number) {
const requestedStatesNumber = getInputNumber("regionsOutput");
if (populatedCells < requestedStatesNumber * 10) {
const maxAllowed = Math.floor(populatedCells / 10);
if (maxAllowed === 0) {
WARN && console.warn("There is no populated cells. Cannot generate states");
return 0;
}
WARN && console.warn(`Not enough populated cells (${populatedCells}). Will generate only ${maxAllowed} states`);
return maxAllowed;
}
return requestedStatesNumber;
}
function assignBurgIds(burgs: TBurgs) {
const burgIds = new Uint16Array(cellsNumber);
for (let i = 1; i < burgs.length; i++) {
const {cell} = burgs[i] as IBurg;
burgIds[cell] = i;
}
return burgIds;
}
}