mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
feat: generateRegiments
This commit is contained in:
parent
3f7f0c4826
commit
c3298ade47
13 changed files with 283 additions and 36 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
export const getDefaultMilitaryOptions: () => IMilitaryUnit[] = function () {
|
export const getDefaultMilitaryOptions: () => IMilitaryUnitConfig[] = function () {
|
||||||
return [
|
return [
|
||||||
{icon: "⚔️", name: "infantry", rural: 0.25, urban: 0.2, crew: 1, power: 1, type: "melee", separate: 0},
|
{icon: "⚔️", name: "infantry", rural: 0.25, urban: 0.2, crew: 1, power: 1, type: "melee", separate: 0},
|
||||||
{icon: "🏹", name: "archers", rural: 0.12, urban: 0.2, crew: 1, power: 1, type: "ranged", separate: 0},
|
{icon: "🏹", name: "archers", rural: 0.12, urban: 0.2, crew: 1, power: 1, type: "ranged", separate: 0},
|
||||||
|
|
@ -32,7 +32,9 @@ export const stateModifier: {[key in TMilitaryUnitType]: {[key in TCultureType]:
|
||||||
magical: {Generic: 1, Nomadic: 1, Highland: 2, Lake: 1, Naval: 1, Hunting: 1, River: 1}
|
magical: {Generic: 1, Nomadic: 1, Highland: 2, Lake: 1, Naval: 1, Hunting: 1, River: 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cellTypeModifier: {[key: string]: {[key in TMilitaryUnitType]: number}} = {
|
type TCellType = "nomadic" | "wetland" | "highland";
|
||||||
|
|
||||||
|
export const cellTypeModifier: {[key in TCellType]: {[key in TMilitaryUnitType]: number}} = {
|
||||||
nomadic: {
|
nomadic: {
|
||||||
melee: 0.2,
|
melee: 0.2,
|
||||||
ranged: 0.5,
|
ranged: 0.5,
|
||||||
|
|
@ -65,7 +67,7 @@ export const cellTypeModifier: {[key: string]: {[key in TMilitaryUnitType]: numb
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const burgTypeModifier: {[key: string]: {[key in TMilitaryUnitType]: number}} = {
|
export const burgTypeModifier: {[key in TCellType]: {[key in TMilitaryUnitType]: number}} = {
|
||||||
nomadic: {
|
nomadic: {
|
||||||
melee: 0.3,
|
melee: 0.3,
|
||||||
ranged: 0.8,
|
ranged: 0.8,
|
||||||
|
|
|
||||||
|
|
@ -305,8 +305,8 @@ window.Military = (function () {
|
||||||
.map((r, i) => {
|
.map((r, i) => {
|
||||||
const u = {};
|
const u = {};
|
||||||
u[r.u] = r.a;
|
u[r.u] = r.a;
|
||||||
(r.childen || []).forEach(n => (u[n.u] = u[n.u] ? (u[n.u] += n.a) : n.a));
|
r.childen?.forEach(n => (u[n.u] = u[n.u] ? (u[n.u] += n.a) : n.a));
|
||||||
return {i, a: r.t, cell: r.cell, x: r.x, y: r.y, bx: r.x, by: r.y, u, n: r.n, name, state: s.i};
|
return {i, a: r.t, cell: r.cell, x: r.x, y: r.y, bx: r.x, by: r.y, u, n: r.n, state: s.i};
|
||||||
});
|
});
|
||||||
|
|
||||||
// generate name for regiments
|
// generate name for regiments
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,38 @@
|
||||||
import {TIME} from "config/logging";
|
import {TIME} from "config/logging";
|
||||||
import {getDefaultMilitaryOptions} from "config/military";
|
import {getDefaultMilitaryOptions} from "config/military";
|
||||||
|
import {isState} from "utils/typeUtils";
|
||||||
import {generatePlatoons} from "./generatePlatoons";
|
import {generatePlatoons} from "./generatePlatoons";
|
||||||
|
import {generateRegiments} from "./generateRegiments";
|
||||||
import {getUnitModifiers} from "./getUnitModifiers";
|
import {getUnitModifiers} from "./getUnitModifiers";
|
||||||
|
|
||||||
export type TCellsData = Pick<
|
export type TCellsData = Pick<
|
||||||
IPack["cells"],
|
IPack["cells"],
|
||||||
"i" | "p" | "h" | "f" | "haven" | "pop" | "biome" | "culture" | "state" | "burg" | "religion"
|
"i" | "p" | "h" | "f" | "haven" | "pop" | "biome" | "culture" | "state" | "burg" | "province" | "religion"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface IPlatoon {
|
export function generateMilitary(states: TStates, burgs: TBurgs, provinces: TProvinces, cells: TCellsData) {
|
||||||
unit: IMilitaryUnit;
|
|
||||||
cell: number;
|
|
||||||
a: number;
|
|
||||||
t: number;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateMilitary(states: TStates, burgs: TBurgs, cells: TCellsData) {
|
|
||||||
TIME && console.time("generateMilitaryForces");
|
TIME && console.time("generateMilitaryForces");
|
||||||
|
|
||||||
if (!options.military) options.military = getDefaultMilitaryOptions();
|
if (!options.military) options.military = getDefaultMilitaryOptions();
|
||||||
|
|
||||||
const unitModifiers = getUnitModifiers(states);
|
const unitModifiers = getUnitModifiers(states);
|
||||||
const platoons = generatePlatoons(states, unitModifiers, cells);
|
const platoons = generatePlatoons(states, burgs, unitModifiers, cells);
|
||||||
|
|
||||||
console.log({states, unitModifiers, platoons});
|
for (const state of states) {
|
||||||
|
if (!isState(state)) continue;
|
||||||
|
|
||||||
|
state.regiments = generateRegiments({
|
||||||
|
stateId: state.i,
|
||||||
|
platoons: platoons[state.i],
|
||||||
|
states,
|
||||||
|
provinceIds: cells.province,
|
||||||
|
provinces,
|
||||||
|
burgIds: cells.burg,
|
||||||
|
burgs
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({states});
|
||||||
|
|
||||||
TIME && console.timeEnd("generateMilitaryForces");
|
TIME && console.timeEnd("generateMilitaryForces");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,15 @@ import {ELEVATION, NOMADIC_BIOMES, WETLAND_BIOMES} from "config/generation";
|
||||||
import {burgTypeModifier, cellTypeModifier} from "config/military";
|
import {burgTypeModifier, cellTypeModifier} from "config/military";
|
||||||
import {rn} from "utils/numberUtils";
|
import {rn} from "utils/numberUtils";
|
||||||
import {isBurg, isState} from "utils/typeUtils";
|
import {isBurg, isState} from "utils/typeUtils";
|
||||||
import {IPlatoon, TCellsData} from "./generateMilitary";
|
import {TCellsData} from "./generateMilitary";
|
||||||
|
|
||||||
|
export interface IPlatoon {
|
||||||
|
unit: IMilitaryUnitConfig;
|
||||||
|
cell: number;
|
||||||
|
total: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
export function generatePlatoons(states: TStates, burgs: TBurgs, unitModifiers: Dict<number>[], cells: TCellsData) {
|
export function generatePlatoons(states: TStates, burgs: TBurgs, unitModifiers: Dict<number>[], cells: TCellsData) {
|
||||||
const platoons: {[key: number]: IPlatoon[]} = {};
|
const platoons: {[key: number]: IPlatoon[]} = {};
|
||||||
|
|
@ -32,13 +40,14 @@ export function generatePlatoons(states: TStates, burgs: TBurgs, unitModifiers:
|
||||||
|
|
||||||
const stateModifiers = unitModifiers[stateId];
|
const stateModifiers = unitModifiers[stateId];
|
||||||
const cellType = getCellType(biomeId, cells.h[i]);
|
const cellType = getCellType(biomeId, cells.h[i]);
|
||||||
|
const isGeneric = cellType === "generic";
|
||||||
|
|
||||||
for (const unit of options.military) {
|
for (const unit of options.military) {
|
||||||
if (!checkUnitConstrains(unit, biomeId, stateId, cultureId, religionId)) continue;
|
if (!checkUnitConstrains(unit, biomeId, stateId, cultureId, religionId)) continue;
|
||||||
if (unit.type === "naval" && !isNavyProducer(cells.haven[i], burg)) continue;
|
if (unit.type === "naval" && !isNavyProducer(cells.haven[i], burg)) continue;
|
||||||
|
|
||||||
const ruralUnitModifier = cellTypeModifier[cellType][unit.type];
|
const ruralUnitModifier = isGeneric ? 1 : cellTypeModifier[cellType][unit.type];
|
||||||
const urbanUnitModifier = burgTypeModifier[cellType][unit.type];
|
const urbanUnitModifier = isGeneric ? 1 : burgTypeModifier[cellType][unit.type];
|
||||||
|
|
||||||
const ruralArmy = ruralBase * unit.rural * ruralUnitModifier * cellModifier * stateModifiers[unit.name];
|
const ruralArmy = ruralBase * unit.rural * ruralUnitModifier * cellModifier * stateModifiers[unit.name];
|
||||||
const urbanArmy = urbanBase * unit.urban * urbanUnitModifier * cellModifier * stateModifiers[unit.name];
|
const urbanArmy = urbanBase * unit.urban * urbanUnitModifier * cellModifier * stateModifiers[unit.name];
|
||||||
|
|
@ -50,7 +59,7 @@ export function generatePlatoons(states: TStates, burgs: TBurgs, unitModifiers:
|
||||||
const [x, y] = cells.p[placeCell];
|
const [x, y] = cells.p[placeCell];
|
||||||
|
|
||||||
if (!platoons[stateId]) platoons[stateId] = [];
|
if (!platoons[stateId]) platoons[stateId] = [];
|
||||||
platoons[stateId].push({unit, cell: i, a: total, t: total, x, y});
|
platoons[stateId].push({unit, cell: i, total, x, y});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,7 +101,13 @@ function getCellType(biomeId: number, cellHeight: number) {
|
||||||
return "generic";
|
return "generic";
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkUnitConstrains(unit: IMilitaryUnit, biome: number, state: number, culture: number, religion: number) {
|
function checkUnitConstrains(
|
||||||
|
unit: IMilitaryUnitConfig,
|
||||||
|
biome: number,
|
||||||
|
state: number,
|
||||||
|
culture: number,
|
||||||
|
religion: number
|
||||||
|
) {
|
||||||
if (unit.biomes?.length && !unit.biomes.includes(biome)) return false;
|
if (unit.biomes?.length && !unit.biomes.includes(biome)) return false;
|
||||||
if (unit.states?.length && !unit.states.includes(state)) return false;
|
if (unit.states?.length && !unit.states.includes(state)) return false;
|
||||||
if (unit.cultures?.length && !unit.cultures.includes(culture)) return false;
|
if (unit.cultures?.length && !unit.cultures.includes(culture)) return false;
|
||||||
|
|
|
||||||
113
src/scripts/generation/pack/military/generateRegiments.ts
Normal file
113
src/scripts/generation/pack/military/generateRegiments.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import * as d3 from "d3";
|
||||||
|
|
||||||
|
import {getName, getEmblem, generateNote} from "./specifyRegiments";
|
||||||
|
import type {IPlatoon} from "./generatePlatoons";
|
||||||
|
|
||||||
|
const MIN_DISTANCE = 20;
|
||||||
|
|
||||||
|
export function generateRegiments({
|
||||||
|
stateId,
|
||||||
|
platoons,
|
||||||
|
states,
|
||||||
|
provinceIds,
|
||||||
|
provinces,
|
||||||
|
burgIds,
|
||||||
|
burgs
|
||||||
|
}: {
|
||||||
|
stateId: number;
|
||||||
|
platoons: IPlatoon[];
|
||||||
|
states: TStates;
|
||||||
|
provinceIds: Uint16Array;
|
||||||
|
provinces: TProvinces;
|
||||||
|
burgIds: Uint16Array;
|
||||||
|
burgs: TBurgs;
|
||||||
|
}): IRegiment[] {
|
||||||
|
const regiments: IRegiment[] = [];
|
||||||
|
if (!platoons.length) return regiments;
|
||||||
|
|
||||||
|
platoons.sort((a, b) => a.total - b.total);
|
||||||
|
const tree = d3.quadtree(
|
||||||
|
platoons,
|
||||||
|
d => d.x,
|
||||||
|
d => d.y
|
||||||
|
) as Quadtree<IPlatoon>;
|
||||||
|
|
||||||
|
const removed = new Set<IPlatoon>();
|
||||||
|
const remove = (platoon: IPlatoon) => {
|
||||||
|
tree.remove(platoon);
|
||||||
|
removed.add(platoon);
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedSize = 3 * populationRate; // expected regiment size is about 3k
|
||||||
|
|
||||||
|
for (const platoon of platoons) {
|
||||||
|
if (removed.has(platoon)) continue;
|
||||||
|
remove(platoon);
|
||||||
|
|
||||||
|
const regimentPlatoons = [platoon];
|
||||||
|
let regimentForce = platoon.total;
|
||||||
|
|
||||||
|
// join all overlapping mergeable platoons
|
||||||
|
const overlapping = tree.findAll(platoon.x, platoon.y, MIN_DISTANCE);
|
||||||
|
|
||||||
|
for (const overlappingPlatoon of overlapping) {
|
||||||
|
if (!isMergeable(platoon, overlappingPlatoon)) continue;
|
||||||
|
regimentPlatoons.push(overlappingPlatoon);
|
||||||
|
regimentForce += overlappingPlatoon.total;
|
||||||
|
remove(overlappingPlatoon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regimentForce >= expectedSize) continue;
|
||||||
|
// if joined force is still too small, check platoons in further range
|
||||||
|
|
||||||
|
const radius = (expectedSize - platoon.total) / MIN_DISTANCE;
|
||||||
|
const candidates = tree.findAll(platoon.x, platoon.y, radius);
|
||||||
|
for (const candidatePlatoon of candidates) {
|
||||||
|
if (candidatePlatoon.total >= expectedSize) break;
|
||||||
|
if (!isMergeable(platoon, candidatePlatoon)) continue;
|
||||||
|
|
||||||
|
regimentPlatoons.push(candidatePlatoon);
|
||||||
|
regimentForce += candidatePlatoon.total;
|
||||||
|
remove(candidatePlatoon);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
regiments.push({
|
||||||
|
i: regiments.length,
|
||||||
|
icon: "", // define below
|
||||||
|
name: "", // define below
|
||||||
|
state: stateId,
|
||||||
|
cell: platoon.cell,
|
||||||
|
x: platoon.x,
|
||||||
|
y: platoon.y,
|
||||||
|
bx: platoon.x,
|
||||||
|
by: platoon.y,
|
||||||
|
total: regimentForce,
|
||||||
|
units: getRegimentUnits(regimentPlatoons),
|
||||||
|
isNaval: platoon.unit.type === "naval"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const regiment of regiments) {
|
||||||
|
regiment.name = getName(regiment, regiments, provinceIds, burgIds, provinces, burgs);
|
||||||
|
regiment.icon = getEmblem(regiment, states, burgs, burgIds);
|
||||||
|
generateNote(regiment, provinceIds, burgIds, provinces, burgs); // TODO: move out of military generation
|
||||||
|
}
|
||||||
|
|
||||||
|
return regiments;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if 2 plattons can be merged
|
||||||
|
function isMergeable(platoon1: IPlatoon, platoon2: IPlatoon) {
|
||||||
|
return platoon1.unit.name === platoon2.unit.name || (!platoon1.unit.separate && !platoon2.unit.separate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRegimentUnits(platoons: IPlatoon[]) {
|
||||||
|
const units: {[key: string]: number} = {};
|
||||||
|
for (const platoon of platoons) {
|
||||||
|
if (!units[platoon.unit.name]) units[platoon.unit.name] = 0;
|
||||||
|
units[platoon.unit.name] += platoon.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
return units;
|
||||||
|
}
|
||||||
92
src/scripts/generation/pack/military/specifyRegiments.ts
Normal file
92
src/scripts/generation/pack/military/specifyRegiments.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import {nth} from "utils/languageUtils";
|
||||||
|
import {gauss} from "utils/probabilityUtils";
|
||||||
|
import {isBurg, isProvince, isState} from "utils/typeUtils";
|
||||||
|
|
||||||
|
export const getName = (
|
||||||
|
regiment: IRegiment,
|
||||||
|
regiments: IRegiment[],
|
||||||
|
provinceIds: Uint16Array,
|
||||||
|
burgIds: Uint16Array,
|
||||||
|
provinces: TProvinces,
|
||||||
|
burgs: TBurgs
|
||||||
|
) => {
|
||||||
|
const proper = getProperName();
|
||||||
|
const number = nth(regiments.filter(reg => reg.isNaval === regiment.isNaval && reg.i < regiment.i).length + 1);
|
||||||
|
const form = regiment.isNaval ? "Fleet" : "Regiment";
|
||||||
|
return `${number}${proper ? ` (${proper}) ` : ` `}${form}`;
|
||||||
|
|
||||||
|
function getProperName() {
|
||||||
|
if (regiment.isNaval) return null;
|
||||||
|
|
||||||
|
const province = provinces[provinceIds[regiment.cell]];
|
||||||
|
if (isProvince(province)) return province.name;
|
||||||
|
|
||||||
|
const burg = burgs[burgIds[regiment.cell]];
|
||||||
|
if (isBurg(burg)) return burg.name;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getEmblem = (regiment: IRegiment, states: TStates, burgs: TBurgs, burgIds: Uint16Array) => {
|
||||||
|
if (regiment.isNaval) return "🌊"; //
|
||||||
|
if (!regiment.isNaval && !regiment.total) return "🔰"; // "Newbie": regiment without troops
|
||||||
|
|
||||||
|
const state = states[regiment.state];
|
||||||
|
const isMonarchy = isState(state) && state.form === "Monarchy";
|
||||||
|
|
||||||
|
const burg = burgs[burgIds[regiment.cell]];
|
||||||
|
const isCapital = isBurg(burg) && burg.capital;
|
||||||
|
|
||||||
|
if (isMonarchy && isCapital) return "👑"; // "Royal" regiment based in capital
|
||||||
|
|
||||||
|
// unit with more troops in regiment
|
||||||
|
const largestUnitName = Object.entries(regiment.units).sort((a, b) => b[1] - a[1])[0][0];
|
||||||
|
const unit = options.military.find(unit => unit.name === largestUnitName);
|
||||||
|
return unit?.icon || "🎖️";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateNote = (
|
||||||
|
regiment: IRegiment,
|
||||||
|
provinceIds: Uint16Array,
|
||||||
|
burgIds: Uint16Array,
|
||||||
|
provinces: TProvinces,
|
||||||
|
burgs: TBurgs
|
||||||
|
) => {
|
||||||
|
const baseName = getBaseName();
|
||||||
|
const station = baseName ? `${regiment.name} is ${regiment.isNaval ? "based" : "stationed"} in ${baseName}. ` : "";
|
||||||
|
const troops = getTroopsComposition() || "";
|
||||||
|
|
||||||
|
// TODO: add campaigns
|
||||||
|
// const campaign = state.campaigns ? ra(state.campaigns) : null;
|
||||||
|
// const year = campaign ? rand(campaign.start, campaign.end) : gauss(options.year - 100, 150, 1, options.year - 6);
|
||||||
|
// const conflict = campaign ? ` during the ${campaign.name}` : "";
|
||||||
|
// const legend = `Regiment was formed in ${year} ${options.era}${conflict}. ${station}${troops}`;
|
||||||
|
|
||||||
|
const year = gauss(options.year - 100, 150, 1, options.year - 6);
|
||||||
|
const legend = `Regiment was formed in ${year} ${options.era}. ${station}${troops}`;
|
||||||
|
|
||||||
|
const id = `regiment${regiment.state}-${regiment.i}`;
|
||||||
|
const name = `${regiment.icon} ${regiment.name}`;
|
||||||
|
notes.push({id, name, legend});
|
||||||
|
|
||||||
|
function getBaseName() {
|
||||||
|
const burg = burgs[burgIds[regiment.cell]];
|
||||||
|
if (isBurg(burg)) return burg.name;
|
||||||
|
|
||||||
|
const province = provinces[provinceIds[regiment.cell]];
|
||||||
|
if (isProvince(province)) return province.fullName;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTroopsComposition() {
|
||||||
|
if (regiment.total) return null;
|
||||||
|
|
||||||
|
const composition = Object.keys(regiment.units)
|
||||||
|
.map(t => `— ${t}: ${regiment.units[t]}`)
|
||||||
|
.join("\r\n");
|
||||||
|
|
||||||
|
return `\r\n\r\nRegiment composition in ${options.year} ${options.eraShort}:\r\n${composition}.`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -164,7 +164,7 @@ export function createPack(grid: IGrid): IPack {
|
||||||
const rivers = specifyRivers(rawRivers, cultureIds, cultures);
|
const rivers = specifyRivers(rawRivers, cultureIds, cultures);
|
||||||
const features = generateLakeNames(mergedFeatures, cultureIds, cultures);
|
const features = generateLakeNames(mergedFeatures, cultureIds, cultures);
|
||||||
|
|
||||||
generateMilitary(states, burgs, {
|
generateMilitary(states, burgs, provinces, {
|
||||||
i: cells.i,
|
i: cells.i,
|
||||||
p: cells.p,
|
p: cells.p,
|
||||||
h: heights,
|
h: heights,
|
||||||
|
|
@ -175,6 +175,7 @@ export function createPack(grid: IGrid): IPack {
|
||||||
culture: cultureIds,
|
culture: cultureIds,
|
||||||
state: stateIds,
|
state: stateIds,
|
||||||
burg: burgIds,
|
burg: burgIds,
|
||||||
|
province: provinceIds,
|
||||||
religion: religionIds
|
religion: religionIds
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export function repackGrid(grid: IGrid) {
|
||||||
...cells,
|
...cells,
|
||||||
p: newCells.p,
|
p: newCells.p,
|
||||||
g: createTypedArray({maxValue: grid.points.length, from: newCells.g}),
|
g: createTypedArray({maxValue: grid.points.length, from: newCells.g}),
|
||||||
q: d3.quadtree(newCells.p.map(([x, y], i) => [x, y, i])) as unknown as Quadtree,
|
q: d3.quadtree(newCells.p.map(([x, y], i) => [x, y, i])),
|
||||||
h: new Uint8Array(newCells.h),
|
h: new Uint8Array(newCells.h),
|
||||||
area: createTypedArray({maxValue: UINT16_MAX, from: cells.i}).map(getCellArea)
|
area: createTypedArray({maxValue: UINT16_MAX, from: cells.i}).map(getCellArea)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
src/types/globals.d.ts
vendored
4
src/types/globals.d.ts
vendored
|
|
@ -26,7 +26,9 @@ interface IOptions {
|
||||||
winds: [number, number, number, number, number, number];
|
winds: [number, number, number, number, number, number];
|
||||||
stateLabelsMode: "auto" | "short" | "full";
|
stateLabelsMode: "auto" | "short" | "full";
|
||||||
year: number;
|
year: number;
|
||||||
military: IMilitaryUnit[];
|
era: string;
|
||||||
|
eraShort: string;
|
||||||
|
military: IMilitaryUnitConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare let populationRate: number;
|
declare let populationRate: number;
|
||||||
|
|
|
||||||
5
src/types/overrides.d.ts
vendored
5
src/types/overrides.d.ts
vendored
|
|
@ -36,7 +36,6 @@ interface Node {
|
||||||
off: (name: string, fn: EventListenerOrEventListenerObject) => void;
|
off: (name: string, fn: EventListenerOrEventListenerObject) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Quadtree extends d3.Quadtree<Number> {
|
interface Quadtree<T> extends d3.Quadtree<T> {
|
||||||
find: (x: number, y: number, radius: number) => [x: number, y: number, cellId: number];
|
findAll: (x: number, y: number, radius: number) => T[];
|
||||||
findAll: (x: number, y: number, radius: number) => [x: number, y: number, cellId: number][];
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
src/types/pack/pack.d.ts
vendored
2
src/types/pack/pack.d.ts
vendored
|
|
@ -32,7 +32,7 @@ interface IPackCells {
|
||||||
haven: UintArray;
|
haven: UintArray;
|
||||||
harbor: UintArray;
|
harbor: UintArray;
|
||||||
route: Uint8Array; // [0, 1, 2, 3], see ROUTES enum, defined by generateRoutes()
|
route: Uint8Array; // [0, 1, 2, 3], see ROUTES enum, defined by generateRoutes()
|
||||||
q: Quadtree;
|
q: Quadtree<number[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPackBase extends IGraph {
|
interface IPackBase extends IGraph {
|
||||||
|
|
|
||||||
26
src/types/pack/states.d.ts
vendored
26
src/types/pack/states.d.ts
vendored
|
|
@ -20,6 +20,7 @@ interface IState {
|
||||||
neighbors: number[];
|
neighbors: number[];
|
||||||
relations: TRelation[];
|
relations: TRelation[];
|
||||||
alert: number;
|
alert: number;
|
||||||
|
regiments: IRegiment[];
|
||||||
removed?: boolean;
|
removed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +54,7 @@ type TRelation =
|
||||||
| "Enemy"
|
| "Enemy"
|
||||||
| "x";
|
| "x";
|
||||||
|
|
||||||
interface IMilitaryUnit {
|
interface IMilitaryUnitConfig {
|
||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
crew: number;
|
crew: number;
|
||||||
|
|
@ -62,10 +63,25 @@ interface IMilitaryUnit {
|
||||||
urban: number;
|
urban: number;
|
||||||
type: TMilitaryUnitType;
|
type: TMilitaryUnitType;
|
||||||
separate: Logical;
|
separate: Logical;
|
||||||
biomes?: number[];
|
biomes?: number[]; // allowed biomes
|
||||||
states?: number[];
|
states?: number[]; // allowed states
|
||||||
cultures?: number[];
|
cultures?: number[]; // allowed cultures
|
||||||
religions?: number[];
|
religions?: number[]; // allowed religions
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRegiment {
|
||||||
|
i: number;
|
||||||
|
icon: string;
|
||||||
|
name: string;
|
||||||
|
state: number; // stateId
|
||||||
|
cell: number; // base cell
|
||||||
|
x: number; // current position x
|
||||||
|
y: number; // current position y
|
||||||
|
bx: number; // base position x
|
||||||
|
by: number; // base position y
|
||||||
|
total: number;
|
||||||
|
units: {[key: string]: number};
|
||||||
|
isNaval: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TMilitaryUnitType = "melee" | "ranged" | "mounted" | "machinery" | "naval" | "armored" | "aviation" | "magical";
|
type TMilitaryUnitType = "melee" | "ranged" | "mounted" | "machinery" | "naval" | "armored" | "aviation" | "magical";
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function findCell(x: number, y: number): number;
|
||||||
export function findCell(x: number, y: number, radius: number): number | undefined;
|
export function findCell(x: number, y: number, radius: number): number | undefined;
|
||||||
export function findCell(x: number, y: number, radius = Infinity): number | undefined {
|
export function findCell(x: number, y: number, radius = Infinity): number | undefined {
|
||||||
const found = pack.cells.q.find(x, y, radius);
|
const found = pack.cells.q.find(x, y, radius);
|
||||||
return found ? found[2] : undefined;
|
return found?.[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// get polygon points for initial cells knowing cell id
|
// get polygon points for initial cells knowing cell id
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue