mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
feat: routes - change data format
This commit is contained in:
parent
597f6ddd75
commit
b47fa6b92d
14 changed files with 155 additions and 139 deletions
20
main.js
20
main.js
|
|
@ -1652,9 +1652,10 @@ function addZones(number = 1) {
|
||||||
const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg
|
const burg = ra(burgs.filter(b => !used[b.cell] && b.i && !b.removed)); // random burg
|
||||||
if (!burg) return;
|
if (!burg) return;
|
||||||
|
|
||||||
const cellsArray = [],
|
const cellsArray = [];
|
||||||
cost = [],
|
const cost = [];
|
||||||
power = rand(20, 37);
|
const power = rand(20, 37);
|
||||||
|
|
||||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
||||||
queue.queue({e: burg.cell, p: 0});
|
queue.queue({e: burg.cell, p: 0});
|
||||||
|
|
||||||
|
|
@ -1663,15 +1664,14 @@ function addZones(number = 1) {
|
||||||
if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e);
|
if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e);
|
||||||
used[next.e] = 1;
|
used[next.e] = 1;
|
||||||
|
|
||||||
cells.c[next.e].forEach(function (e) {
|
cells.c[next.e].forEach(nextCellId => {
|
||||||
const r = cells.route[next.e];
|
const c = Routes.getRoute(next.e, nextCellId) ? 5 : 100;
|
||||||
const c = r ? 5 : 100;
|
|
||||||
const p = next.p + c;
|
const p = next.p + c;
|
||||||
if (p > power) return;
|
if (p > power) return;
|
||||||
|
|
||||||
if (!cost[e] || p < cost[e]) {
|
if (!cost[nextCellId] || p < cost[nextCellId]) {
|
||||||
cost[e] = p;
|
cost[nextCellId] = p;
|
||||||
queue.queue({e, p});
|
queue.queue({e: nextCellId, p});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1792,7 +1792,7 @@ function addZones(number = 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAvalanche() {
|
function addAvalanche() {
|
||||||
const routes = cells.i.filter(i => !used[i] && cells.route[i] && cells.h[i] >= 70);
|
const routes = cells.i.filter(i => !used[i] && Routes.isConnected(i) && cells.h[i] >= 70);
|
||||||
if (!routes.length) return;
|
if (!routes.length) return;
|
||||||
|
|
||||||
const cell = +ra(routes);
|
const cell = +ra(routes);
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
window.Biomes = (function () {
|
||||||
const MIN_LAND_HEIGHT = 20;
|
const MIN_LAND_HEIGHT = 20;
|
||||||
|
|
||||||
const names = [
|
|
||||||
"Marine",
|
|
||||||
"Hot desert",
|
|
||||||
"Cold desert",
|
|
||||||
"Savanna",
|
|
||||||
"Grassland",
|
|
||||||
"Tropical seasonal forest",
|
|
||||||
"Temperate deciduous forest",
|
|
||||||
"Tropical rainforest",
|
|
||||||
"Temperate rainforest",
|
|
||||||
"Taiga",
|
|
||||||
"Tundra",
|
|
||||||
"Glacier",
|
|
||||||
"Wetland"
|
|
||||||
];
|
|
||||||
|
|
||||||
window.Biomes = (function () {
|
|
||||||
const getDefault = () => {
|
const getDefault = () => {
|
||||||
const name = [
|
const name = [
|
||||||
"Marine",
|
"Marine",
|
||||||
|
|
@ -52,7 +36,7 @@ window.Biomes = (function () {
|
||||||
"#0b9131"
|
"#0b9131"
|
||||||
];
|
];
|
||||||
const habitability = [0, 4, 10, 22, 30, 50, 100, 80, 90, 12, 4, 0, 12];
|
const habitability = [0, 4, 10, 22, 30, 50, 100, 80, 90, 12, 4, 0, 12];
|
||||||
const iconsDensity = [0, 3, 2, 120, 120, 120, 120, 150, 150, 100, 5, 0, 150];
|
const iconsDensity = [0, 3, 2, 120, 120, 120, 120, 150, 150, 100, 5, 0, 250];
|
||||||
const icons = [
|
const icons = [
|
||||||
{},
|
{},
|
||||||
{dune: 3, cactus: 6, deadTree: 1},
|
{dune: 3, cactus: 6, deadTree: 1},
|
||||||
|
|
|
||||||
|
|
@ -846,9 +846,9 @@ export function resolveVersionConflicts(version) {
|
||||||
|
|
||||||
if (version < 1.98) {
|
if (version < 1.98) {
|
||||||
// v1.98.00 changed routes generation algorithm and data format
|
// v1.98.00 changed routes generation algorithm and data format
|
||||||
// 1. cells.road => cells.route; 1 = MAIN; 2 = TRAIL; 3 = SEA;
|
// 1. cells.road => cells.routes and now it an object of objects {i1: {i2: routeId, i3: routeId}}
|
||||||
// 2. cells.crossroad is removed
|
// 2. cells.crossroad is removed
|
||||||
// 3. pack.routes is added
|
// 3. pack.routes is added as an array of objects
|
||||||
// 4. rendering is changed
|
// 4. rendering is changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ function getSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPackCellsData() {
|
function getPackCellsData() {
|
||||||
const dataArrays = {
|
const data = {
|
||||||
v: pack.cells.v,
|
v: pack.cells.v,
|
||||||
c: pack.cells.c,
|
c: pack.cells.c,
|
||||||
p: pack.cells.p,
|
p: pack.cells.p,
|
||||||
|
|
@ -122,7 +122,7 @@ function getPackCellsData() {
|
||||||
pop: Array.from(pack.cells.pop),
|
pop: Array.from(pack.cells.pop),
|
||||||
culture: Array.from(pack.cells.culture),
|
culture: Array.from(pack.cells.culture),
|
||||||
burg: Array.from(pack.cells.burg),
|
burg: Array.from(pack.cells.burg),
|
||||||
route: Array.from(pack.cells.route),
|
routes: pack.cells.routes,
|
||||||
state: Array.from(pack.cells.state),
|
state: Array.from(pack.cells.state),
|
||||||
religion: Array.from(pack.cells.religion),
|
religion: Array.from(pack.cells.religion),
|
||||||
province: Array.from(pack.cells.province)
|
province: Array.from(pack.cells.province)
|
||||||
|
|
@ -131,28 +131,28 @@ function getPackCellsData() {
|
||||||
return {
|
return {
|
||||||
cells: Array.from(pack.cells.i).map(cellId => ({
|
cells: Array.from(pack.cells.i).map(cellId => ({
|
||||||
i: cellId,
|
i: cellId,
|
||||||
v: dataArrays.v[cellId],
|
v: data.v[cellId],
|
||||||
c: dataArrays.c[cellId],
|
c: data.c[cellId],
|
||||||
p: dataArrays.p[cellId],
|
p: data.p[cellId],
|
||||||
g: dataArrays.g[cellId],
|
g: data.g[cellId],
|
||||||
h: dataArrays.h[cellId],
|
h: data.h[cellId],
|
||||||
area: dataArrays.area[cellId],
|
area: data.area[cellId],
|
||||||
f: dataArrays.f[cellId],
|
f: data.f[cellId],
|
||||||
t: dataArrays.t[cellId],
|
t: data.t[cellId],
|
||||||
haven: dataArrays.haven[cellId],
|
haven: data.haven[cellId],
|
||||||
harbor: dataArrays.harbor[cellId],
|
harbor: data.harbor[cellId],
|
||||||
fl: dataArrays.fl[cellId],
|
fl: data.fl[cellId],
|
||||||
r: dataArrays.r[cellId],
|
r: data.r[cellId],
|
||||||
conf: dataArrays.conf[cellId],
|
conf: data.conf[cellId],
|
||||||
biome: dataArrays.biome[cellId],
|
biome: data.biome[cellId],
|
||||||
s: dataArrays.s[cellId],
|
s: data.s[cellId],
|
||||||
pop: dataArrays.pop[cellId],
|
pop: data.pop[cellId],
|
||||||
culture: dataArrays.culture[cellId],
|
culture: data.culture[cellId],
|
||||||
burg: dataArrays.burg[cellId],
|
burg: data.burg[cellId],
|
||||||
route: dataArrays.route[cellId],
|
routes: data.routes[cellId],
|
||||||
state: dataArrays.state[cellId],
|
state: data.state[cellId],
|
||||||
religion: dataArrays.religion[cellId],
|
religion: data.religion[cellId],
|
||||||
province: dataArrays.province[cellId]
|
province: data.province[cellId]
|
||||||
})),
|
})),
|
||||||
vertices: Array.from(pack.vertices.p).map((_, vertexId) => ({
|
vertices: Array.from(pack.vertices.p).map((_, vertexId) => ({
|
||||||
i: vertexId,
|
i: vertexId,
|
||||||
|
|
|
||||||
|
|
@ -374,6 +374,7 @@ async function parseLoadedData(data, mapVersion) {
|
||||||
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
|
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
|
||||||
pack.rivers = data[32] ? JSON.parse(data[32]) : [];
|
pack.rivers = data[32] ? JSON.parse(data[32]) : [];
|
||||||
pack.markers = data[35] ? JSON.parse(data[35]) : [];
|
pack.markers = data[35] ? JSON.parse(data[35]) : [];
|
||||||
|
pack.routes = data[37] ? JSON.parse(data[37]) : [];
|
||||||
|
|
||||||
const cells = pack.cells;
|
const cells = pack.cells;
|
||||||
cells.biome = Uint8Array.from(data[16].split(","));
|
cells.biome = Uint8Array.from(data[16].split(","));
|
||||||
|
|
@ -383,12 +384,13 @@ async function parseLoadedData(data, mapVersion) {
|
||||||
cells.fl = Uint16Array.from(data[20].split(","));
|
cells.fl = Uint16Array.from(data[20].split(","));
|
||||||
cells.pop = Float32Array.from(data[21].split(","));
|
cells.pop = Float32Array.from(data[21].split(","));
|
||||||
cells.r = Uint16Array.from(data[22].split(","));
|
cells.r = Uint16Array.from(data[22].split(","));
|
||||||
cells.route = Uint8Array.from(data[23].split(","));
|
// data[23] for deprecated cells.road
|
||||||
cells.s = Uint16Array.from(data[24].split(","));
|
cells.s = Uint16Array.from(data[24].split(","));
|
||||||
cells.state = Uint16Array.from(data[25].split(","));
|
cells.state = Uint16Array.from(data[25].split(","));
|
||||||
cells.religion = data[26] ? Uint16Array.from(data[26].split(",")) : new Uint16Array(cells.i.length);
|
cells.religion = data[26] ? Uint16Array.from(data[26].split(",")) : new Uint16Array(cells.i.length);
|
||||||
cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(cells.i.length);
|
cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(cells.i.length);
|
||||||
// data[28] for deprecated cells.crossroad
|
// data[28] for deprecated cells.crossroad
|
||||||
|
cells.routes = data[36] ? JSON.parse(data[36]) : {};
|
||||||
|
|
||||||
if (data[31]) {
|
if (data[31]) {
|
||||||
const namesDL = data[31].split("/");
|
const namesDL = data[31].split("/");
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ function prepareMapData() {
|
||||||
const provinces = JSON.stringify(pack.provinces);
|
const provinces = JSON.stringify(pack.provinces);
|
||||||
const rivers = JSON.stringify(pack.rivers);
|
const rivers = JSON.stringify(pack.rivers);
|
||||||
const markers = JSON.stringify(pack.markers);
|
const markers = JSON.stringify(pack.markers);
|
||||||
|
const cellRoutes = JSON.stringify(pack.cells.routes);
|
||||||
|
const routes = JSON.stringify(pack.routes);
|
||||||
|
|
||||||
// store name array only if not the same as default
|
// store name array only if not the same as default
|
||||||
const defaultNB = Names.getNameBases();
|
const defaultNB = Names.getNameBases();
|
||||||
|
|
@ -135,7 +137,7 @@ function prepareMapData() {
|
||||||
pack.cells.fl,
|
pack.cells.fl,
|
||||||
pop,
|
pop,
|
||||||
pack.cells.r,
|
pack.cells.r,
|
||||||
pack.cells.route,
|
[], // deprecated pack.cells.road
|
||||||
pack.cells.s,
|
pack.cells.s,
|
||||||
pack.cells.state,
|
pack.cells.state,
|
||||||
pack.cells.religion,
|
pack.cells.religion,
|
||||||
|
|
@ -147,7 +149,9 @@ function prepareMapData() {
|
||||||
rivers,
|
rivers,
|
||||||
rulersString,
|
rulersString,
|
||||||
fonts,
|
fonts,
|
||||||
markers
|
markers,
|
||||||
|
cellRoutes,
|
||||||
|
routes
|
||||||
].join("\r\n");
|
].join("\r\n");
|
||||||
return mapData;
|
return mapData;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ window.Markers = (function () {
|
||||||
{type: "water-sources", icon: "💧", min: 1, each: 1000, multiplier: 1, list: listWaterSources, add: addWaterSource},
|
{type: "water-sources", icon: "💧", min: 1, each: 1000, multiplier: 1, list: listWaterSources, add: addWaterSource},
|
||||||
{type: "mines", icon: "⛏️", dx: 48, px: 13, min: 1, each: 15, multiplier: 1, list: listMines, add: addMine},
|
{type: "mines", icon: "⛏️", dx: 48, px: 13, min: 1, each: 15, multiplier: 1, list: listMines, add: addMine},
|
||||||
{type: "bridges", icon: "🌉", px: 14, min: 1, each: 5, multiplier: 1, list: listBridges, add: addBridge},
|
{type: "bridges", icon: "🌉", px: 14, min: 1, each: 5, multiplier: 1, list: listBridges, add: addBridge},
|
||||||
{type: "inns", icon: "🍻", px: 14, min: 1, each: 100, multiplier: 1, list: listInns, add: addInn},
|
{type: "inns", icon: "🍻", px: 14, min: 1, each: 10, multiplier: 1, list: listInns, add: addInn},
|
||||||
{type: "lighthouses", icon: "🚨", px: 14, min: 1, each: 2, multiplier: 1, list: listLighthouses, add: addLighthouse},
|
{type: "lighthouses", icon: "🚨", px: 14, min: 1, each: 2, multiplier: 1, list: listLighthouses, add: addLighthouse},
|
||||||
{type: "waterfalls", icon: "⟱", dy: 54, px: 16, min: 1, each: 5, multiplier: 1, list: listWaterfalls, add: addWaterfall},
|
{type: "waterfalls", icon: "⟱", dy: 54, px: 16, min: 1, each: 5, multiplier: 1, list: listWaterfalls, add: addWaterfall},
|
||||||
{type: "battlefields", icon: "⚔️", dy: 52, min: 50, each: 700, multiplier: 1, list: listBattlefields, add: addBattlefield},
|
{type: "battlefields", icon: "⚔️", dy: 52, min: 50, each: 700, multiplier: 1, list: listBattlefields, add: addBattlefield},
|
||||||
|
|
@ -279,7 +279,8 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function listInns({cells}) {
|
function listInns({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.h[i] >= 20 && cells.route[i] === 1 && cells.pop[i] > 10);
|
const crossRoads = cells.i.filter(i => !occupied[i] && cells.pop[i] > 5 && Routes.isCrossroad(i));
|
||||||
|
return crossRoads;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addInn(id, cell) {
|
function addInn(id, cell) {
|
||||||
|
|
@ -542,7 +543,7 @@ window.Markers = (function () {
|
||||||
|
|
||||||
function listLighthouses({cells}) {
|
function listLighthouses({cells}) {
|
||||||
return cells.i.filter(
|
return cells.i.filter(
|
||||||
i => !occupied[i] && cells.harbor[i] > 6 && cells.c[i].some(c => cells.h[c] < 20 && cells.route[c])
|
i => !occupied[i] && cells.harbor[i] > 6 && cells.c[i].some(c => cells.h[c] < 20 && Routes.isConnected(c))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -642,7 +643,7 @@ window.Markers = (function () {
|
||||||
|
|
||||||
function listSeaMonsters({cells, features}) {
|
function listSeaMonsters({cells, features}) {
|
||||||
return cells.i.filter(
|
return cells.i.filter(
|
||||||
i => !occupied[i] && cells.h[i] < 20 && cells.route[i] && features[cells.f[i]].type === "ocean"
|
i => !occupied[i] && cells.h[i] < 20 && Routes.isConnected(i) && features[cells.f[i]].type === "ocean"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -792,7 +793,7 @@ window.Markers = (function () {
|
||||||
cells.religion[i] &&
|
cells.religion[i] &&
|
||||||
cells.biome[i] === 1 &&
|
cells.biome[i] === 1 &&
|
||||||
cells.pop[i] > 1 &&
|
cells.pop[i] > 1 &&
|
||||||
cells.route[i]
|
Routes.isConnected(i)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -807,7 +808,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function listBrigands({cells}) {
|
function listBrigands({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.route[i] === 1);
|
return cells.i.filter(i => !occupied[i] && cells.culture[i] && Routes.hasRoad(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addBrigands(id, cell) {
|
function addBrigands(id, cell) {
|
||||||
|
|
@ -867,7 +868,7 @@ window.Markers = (function () {
|
||||||
|
|
||||||
// Pirates spawn on sea routes
|
// Pirates spawn on sea routes
|
||||||
function listPirates({cells}) {
|
function listPirates({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.h[i] < 20 && cells.route[i]);
|
return cells.i.filter(i => !occupied[i] && cells.h[i] < 20 && Routes.isConnected(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPirates(id, cell) {
|
function addPirates(id, cell) {
|
||||||
|
|
@ -961,7 +962,7 @@ window.Markers = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function listCircuses({cells}) {
|
function listCircuses({cells}) {
|
||||||
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.h[i] >= 20 && pack.cells.route[i]);
|
return cells.i.filter(i => !occupied[i] && cells.culture[i] && cells.h[i] >= 20 && Routes.isConnected(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCircuse(id, cell) {
|
function addCircuse(id, cell) {
|
||||||
|
|
@ -1254,16 +1255,16 @@ window.Markers = (function () {
|
||||||
|
|
||||||
const name = `${toponym} ${type}`;
|
const name = `${toponym} ${type}`;
|
||||||
const legend = ra([
|
const legend = ra([
|
||||||
"A foreboding necropolis shrouded in perpetual darkness, where eerie whispers echo through the winding corridors and spectral guardians stand watch over the tombs of long-forgotten souls",
|
"A foreboding necropolis shrouded in perpetual darkness, where eerie whispers echo through the winding corridors and spectral guardians stand watch over the tombs of long-forgotten souls.",
|
||||||
"A towering necropolis adorned with macabre sculptures and guarded by formidable undead sentinels. Its ancient halls house the remains of fallen heroes, entombed alongside their cherished relics",
|
"A towering necropolis adorned with macabre sculptures and guarded by formidable undead sentinels. Its ancient halls house the remains of fallen heroes, entombed alongside their cherished relics.",
|
||||||
"This ethereal necropolis seems suspended between the realms of the living and the dead. Wisps of mist dance around the tombstones, while haunting melodies linger in the air, commemorating the departed",
|
"This ethereal necropolis seems suspended between the realms of the living and the dead. Wisps of mist dance around the tombstones, while haunting melodies linger in the air, commemorating the departed.",
|
||||||
"Rising from the desolate landscape, this sinister necropolis is a testament to necromantic power. Its skeletal spires cast ominous shadows, concealing forbidden knowledge and arcane secrets",
|
"Rising from the desolate landscape, this sinister necropolis is a testament to necromantic power. Its skeletal spires cast ominous shadows, concealing forbidden knowledge and arcane secrets.",
|
||||||
"An eerie necropolis where nature intertwines with death. Overgrown tombstones are entwined by thorny vines, and mournful spirits wander among the fading petals of once-vibrant flowers",
|
"An eerie necropolis where nature intertwines with death. Overgrown tombstones are entwined by thorny vines, and mournful spirits wander among the fading petals of once-vibrant flowers.",
|
||||||
"A labyrinthine necropolis where each step echoes with haunting murmurs. The walls are adorned with ancient runes, and restless spirits guide or hinder those who dare to delve into its depths",
|
"A labyrinthine necropolis where each step echoes with haunting murmurs. The walls are adorned with ancient runes, and restless spirits guide or hinder those who dare to delve into its depths.",
|
||||||
"This cursed necropolis is veiled in perpetual twilight, perpetuating a sense of impending doom. Dark enchantments shroud the tombs, and the moans of anguished souls resound through its crumbling halls",
|
"This cursed necropolis is veiled in perpetual twilight, perpetuating a sense of impending doom. Dark enchantments shroud the tombs, and the moans of anguished souls resound through its crumbling halls.",
|
||||||
"A sprawling necropolis built within a labyrinthine network of catacombs. Its halls are lined with countless alcoves, each housing the remains of the departed, while the distant sound of rattling bones fills the air",
|
"A sprawling necropolis built within a labyrinthine network of catacombs. Its halls are lined with countless alcoves, each housing the remains of the departed, while the distant sound of rattling bones fills the air.",
|
||||||
"A desolate necropolis where an eerie stillness reigns. Time seems frozen amidst the decaying mausoleums, and the silence is broken only by the whispers of the wind and the rustle of tattered banners",
|
"A desolate necropolis where an eerie stillness reigns. Time seems frozen amidst the decaying mausoleums, and the silence is broken only by the whispers of the wind and the rustle of tattered banners.",
|
||||||
"A foreboding necropolis perched atop a jagged cliff, overlooking a desolate wasteland. Its towering walls harbor restless spirits, and the imposing gates bear the marks of countless battles and ancient curses"
|
"A foreboding necropolis perched atop a jagged cliff, overlooking a desolate wasteland. Its towering walls harbor restless spirits, and the imposing gates bear the marks of countless battles and ancient curses."
|
||||||
]);
|
]);
|
||||||
|
|
||||||
notes.push({id, name, legend});
|
notes.push({id, name, legend});
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,7 @@ window.Religions = (function () {
|
||||||
|
|
||||||
// growth algorithm to assign cells to religions
|
// growth algorithm to assign cells to religions
|
||||||
function expandReligions(religions) {
|
function expandReligions(religions) {
|
||||||
const cells = pack.cells;
|
const {cells, routes} = pack;
|
||||||
const religionIds = spreadFolkReligions(religions);
|
const religionIds = spreadFolkReligions(religions);
|
||||||
|
|
||||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
||||||
|
|
@ -700,8 +700,6 @@ window.Religions = (function () {
|
||||||
|
|
||||||
const maxExpansionCost = (cells.i.length / 20) * neutralInput.value; // limit cost for organized religions growth
|
const maxExpansionCost = (cells.i.length / 20) * neutralInput.value; // limit cost for organized religions growth
|
||||||
|
|
||||||
const biomePassageCost = cellId => biomesData.cost[cells.biome[cellId]];
|
|
||||||
|
|
||||||
religions
|
religions
|
||||||
.filter(r => r.i && !r.lock && r.type !== "Folk" && !r.removed)
|
.filter(r => r.i && !r.lock && r.type !== "Folk" && !r.removed)
|
||||||
.forEach(r => {
|
.forEach(r => {
|
||||||
|
|
@ -712,11 +710,6 @@ window.Religions = (function () {
|
||||||
|
|
||||||
const religionsMap = new Map(religions.map(r => [r.i, r]));
|
const religionsMap = new Map(religions.map(r => [r.i, r]));
|
||||||
|
|
||||||
const isMainRoad = cellId => cells.route[cellId] === 1;
|
|
||||||
const isTrail = cellId => cells.route[cellId] === 2;
|
|
||||||
const isSeaRoute = cellId => cells.route[cellId] === 3;
|
|
||||||
const isWater = cellId => cells.h[cellId] < 20;
|
|
||||||
|
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const {e: cellId, p, r, s: state} = queue.dequeue();
|
const {e: cellId, p, r, s: state} = queue.dequeue();
|
||||||
const {culture, expansion, expansionism} = religionsMap.get(r);
|
const {culture, expansion, expansionism} = religionsMap.get(r);
|
||||||
|
|
@ -728,7 +721,7 @@ window.Religions = (function () {
|
||||||
|
|
||||||
const cultureCost = culture !== cells.culture[nextCell] ? 10 : 0;
|
const cultureCost = culture !== cells.culture[nextCell] ? 10 : 0;
|
||||||
const stateCost = state !== cells.state[nextCell] ? 10 : 0;
|
const stateCost = state !== cells.state[nextCell] ? 10 : 0;
|
||||||
const passageCost = getPassageCost(nextCell);
|
const passageCost = getPassageCost(cellId, nextCell);
|
||||||
|
|
||||||
const cellCost = cultureCost + stateCost + passageCost;
|
const cellCost = cultureCost + stateCost + passageCost;
|
||||||
const totalCost = p + 10 + cellCost / expansionism;
|
const totalCost = p + 10 + cellCost / expansionism;
|
||||||
|
|
@ -745,11 +738,18 @@ window.Religions = (function () {
|
||||||
|
|
||||||
return religionIds;
|
return religionIds;
|
||||||
|
|
||||||
function getPassageCost(cellId) {
|
function getPassageCost(cellId, nextCellId) {
|
||||||
if (isWater(cellId)) return isSeaRoute ? 50 : 500;
|
const route = Routes.getRoute(cellId, nextCellId);
|
||||||
if (isMainRoad(cellId)) return 1;
|
if (isWater(cellId)) return route ? 50 : 500;
|
||||||
const biomeCost = biomePassageCost(cellId);
|
|
||||||
return isTrail(cellId) ? biomeCost / 1.5 : biomeCost;
|
const biomePassageCost = biomesData.cost[cells.biome[nextCellId]];
|
||||||
|
|
||||||
|
if (route) {
|
||||||
|
if (route.group === "roads") return 1;
|
||||||
|
return biomePassageCost / 3; // trails and other routes
|
||||||
|
}
|
||||||
|
|
||||||
|
return biomePassageCost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,14 @@
|
||||||
// suggested data format
|
|
||||||
|
|
||||||
// pack.cells.connectivity = {
|
|
||||||
// cellId1: {
|
|
||||||
// toCellId2: routeId2,
|
|
||||||
// toCellId3: routeId2,
|
|
||||||
// },
|
|
||||||
// cellId2: {
|
|
||||||
// toCellId1: routeId2,
|
|
||||||
// toCellId3: routeId1,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pack.routes = [
|
|
||||||
// {i, group: "roads", feature: featureId, cells: [cellId], points?: [[x, y], [x, y]]}
|
|
||||||
// ];
|
|
||||||
|
|
||||||
window.Routes = (function () {
|
window.Routes = (function () {
|
||||||
const ROUTES = {
|
|
||||||
MAIN_ROAD: 1,
|
|
||||||
TRAIL: 2,
|
|
||||||
SEA_ROUTE: 3
|
|
||||||
};
|
|
||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
const {cells, burgs} = pack;
|
const {capitalsByFeature, burgsByFeature, portsByFeature} = sortBurgsByFeature(pack.burgs);
|
||||||
const cellRoutes = new Uint8Array(cells.h.length);
|
|
||||||
|
|
||||||
const {capitalsByFeature, burgsByFeature, portsByFeature} = sortBurgsByFeature(burgs);
|
|
||||||
const connections = new Map();
|
const connections = new Map();
|
||||||
|
|
||||||
const mainRoads = generateMainRoads();
|
const mainRoads = generateMainRoads();
|
||||||
const trails = generateTrails();
|
const trails = generateTrails();
|
||||||
const seaRoutes = generateSeaRoutes();
|
const seaRoutes = generateSeaRoutes();
|
||||||
|
|
||||||
cells.route = cellRoutes;
|
|
||||||
pack.routes = combineRoutes();
|
pack.routes = combineRoutes();
|
||||||
|
pack.cells.routes = buildLinks(pack.routes);
|
||||||
|
|
||||||
function sortBurgsByFeature(burgs) {
|
function sortBurgsByFeature(burgs) {
|
||||||
const burgsByFeature = {};
|
const burgsByFeature = {};
|
||||||
|
|
@ -71,7 +45,7 @@ window.Routes = (function () {
|
||||||
|
|
||||||
const segments = findPathSegments({isWater: false, connections, start, exit});
|
const segments = findPathSegments({isWater: false, connections, start, exit});
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
addConnections(segment, ROUTES.MAIN_ROAD);
|
addConnections(segment);
|
||||||
mainRoads.push({feature: Number(key), cells: segment});
|
mainRoads.push({feature: Number(key), cells: segment});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -94,7 +68,7 @@ window.Routes = (function () {
|
||||||
|
|
||||||
const segments = findPathSegments({isWater: false, connections, start, exit});
|
const segments = findPathSegments({isWater: false, connections, start, exit});
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
addConnections(segment, ROUTES.TRAIL);
|
addConnections(segment);
|
||||||
trails.push({feature: Number(key), cells: segment});
|
trails.push({feature: Number(key), cells: segment});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -117,7 +91,7 @@ window.Routes = (function () {
|
||||||
const exit = featurePorts[toId].cell;
|
const exit = featurePorts[toId].cell;
|
||||||
const segments = findPathSegments({isWater: true, connections, start, exit});
|
const segments = findPathSegments({isWater: true, connections, start, exit});
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
addConnections(segment, ROUTES.SEA_ROUTE);
|
addConnections(segment);
|
||||||
seaRoutes.push({feature: Number(featureId), cells: segment});
|
seaRoutes.push({feature: Number(featureId), cells: segment});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -127,7 +101,7 @@ window.Routes = (function () {
|
||||||
return seaRoutes;
|
return seaRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addConnections(segment, routeTypeId) {
|
function addConnections(segment) {
|
||||||
for (let i = 0; i < segment.length; i++) {
|
for (let i = 0; i < segment.length; i++) {
|
||||||
const cellId = segment[i];
|
const cellId = segment[i];
|
||||||
const nextCellId = segment[i + 1];
|
const nextCellId = segment[i + 1];
|
||||||
|
|
@ -135,7 +109,6 @@ window.Routes = (function () {
|
||||||
connections.set(`${cellId}-${nextCellId}`, true);
|
connections.set(`${cellId}-${nextCellId}`, true);
|
||||||
connections.set(`${nextCellId}-${cellId}`, true);
|
connections.set(`${nextCellId}-${cellId}`, true);
|
||||||
}
|
}
|
||||||
if (!cellRoutes[cellId]) cellRoutes[cellId] = routeTypeId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,10 +138,29 @@ window.Routes = (function () {
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildLinks(routes) {
|
||||||
|
const links = {};
|
||||||
|
|
||||||
|
for (const {cells, i: routeId} of routes) {
|
||||||
|
for (let i = 0; i < cells.length; i++) {
|
||||||
|
const cellId = cells[i];
|
||||||
|
const nextCellId = cells[i + 1];
|
||||||
|
if (nextCellId) {
|
||||||
|
if (!links[cellId]) links[cellId] = {};
|
||||||
|
links[cellId][nextCellId] = routeId;
|
||||||
|
|
||||||
|
if (!links[nextCellId]) links[nextCellId] = {};
|
||||||
|
links[nextCellId][cellId] = routeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_PASSABLE_SEA_TEMP = -4;
|
const MIN_PASSABLE_SEA_TEMP = -4;
|
||||||
|
|
||||||
const TYPE_MODIFIERS = {
|
const TYPE_MODIFIERS = {
|
||||||
"-1": 1, // coastline
|
"-1": 1, // coastline
|
||||||
"-2": 1.8, // sea
|
"-2": 1.8, // sea
|
||||||
|
|
@ -339,5 +331,36 @@ window.Routes = (function () {
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {generate};
|
// utility functions
|
||||||
|
function isConnected(cellId) {
|
||||||
|
const {routes} = pack.cells;
|
||||||
|
return routes[cellId] && Object.keys(routes[cellId]).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function areConnected(from, to) {
|
||||||
|
const routeId = pack.cells.routes[from]?.[to];
|
||||||
|
return routeId !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRoute(from, to) {
|
||||||
|
const routeId = pack.cells.routes[from]?.[to];
|
||||||
|
return routeId === undefined ? null : pack.routes[routeId];
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasRoad(cellId) {
|
||||||
|
const connections = pack.cells.routes[cellId];
|
||||||
|
if (!connections) return false;
|
||||||
|
return Object.values(connections).some(routeId => pack.routes[routeId].group === "roads");
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCrossroad(cellId) {
|
||||||
|
const connections = pack.cells.routes[cellId];
|
||||||
|
if (!connections) return false;
|
||||||
|
return (
|
||||||
|
Object.keys(connections).length > 3 ||
|
||||||
|
Object.values(connections).filter(routeId => pack.routes[routeId].group === "roads").length > 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {generate, isConnected, areConnected, getRoute, hasRoad, isCrossroad};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,6 @@ window.Submap = (function () {
|
||||||
cells.state = new Uint16Array(pn);
|
cells.state = new Uint16Array(pn);
|
||||||
cells.burg = new Uint16Array(pn);
|
cells.burg = new Uint16Array(pn);
|
||||||
cells.religion = new Uint16Array(pn);
|
cells.religion = new Uint16Array(pn);
|
||||||
cells.route = new Uint8Array(pn);
|
|
||||||
cells.province = new Uint16Array(pn);
|
cells.province = new Uint16Array(pn);
|
||||||
|
|
||||||
stage("Resampling culture, state and religion map.");
|
stage("Resampling culture, state and religion map.");
|
||||||
|
|
|
||||||
|
|
@ -326,8 +326,7 @@ function createMfcgLink(burg) {
|
||||||
const citadel = +burg.citadel;
|
const citadel = +burg.citadel;
|
||||||
const urban_castle = +(citadel && each(2)(i));
|
const urban_castle = +(citadel && each(2)(i));
|
||||||
|
|
||||||
const hub = +cells.route[cell] === 1;
|
const hub = Routes.isCrossroad(cell);
|
||||||
|
|
||||||
const walls = +burg.walls;
|
const walls = +burg.walls;
|
||||||
const plaza = +burg.plaza;
|
const plaza = +burg.plaza;
|
||||||
const temple = +burg.temple;
|
const temple = +burg.temple;
|
||||||
|
|
@ -371,10 +370,12 @@ function createVillageGeneratorLink(burg) {
|
||||||
else if (cells.r[cell]) tags.push("river");
|
else if (cells.r[cell]) tags.push("river");
|
||||||
else if (pop < 200 && each(4)(cell)) tags.push("pond");
|
else if (pop < 200 && each(4)(cell)) tags.push("pond");
|
||||||
|
|
||||||
const roadsAround = cells.c[cell].filter(c => cells.h[c] >= 20 && cells.route[c]).length;
|
const connections = pack.cells.routes[cell] || {};
|
||||||
if (roadsAround > 1) tags.push("highway");
|
const roads = Object.values(connections).filter(routeId => {
|
||||||
else if (roadsAround === 1) tags.push("dead end");
|
const route = pack.routes[routeId];
|
||||||
else tags.push("isolated");
|
return route.group === "roads" || route.group === "trails";
|
||||||
|
}).length;
|
||||||
|
tags.push(roads > 1 ? "highway" : roads === 1 ? "dead end" : "isolated");
|
||||||
|
|
||||||
const biome = cells.biome[cell];
|
const biome = cells.biome[cell];
|
||||||
const arableBiomes = cells.r[cell] ? [1, 2, 3, 4, 5, 6, 7, 8] : [5, 6, 7, 8];
|
const arableBiomes = cells.r[cell] ? [1, 2, 3, 4, 5, 6, 7, 8] : [5, 6, 7, 8];
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ function editHeightmap(options) {
|
||||||
const l = grid.cells.i.length;
|
const l = grid.cells.i.length;
|
||||||
const biome = new Uint8Array(l);
|
const biome = new Uint8Array(l);
|
||||||
const pop = new Uint16Array(l);
|
const pop = new Uint16Array(l);
|
||||||
const route = new Uint8Array(l);
|
const routes = {};
|
||||||
const s = new Uint16Array(l);
|
const s = new Uint16Array(l);
|
||||||
const burg = new Uint16Array(l);
|
const burg = new Uint16Array(l);
|
||||||
const state = new Uint16Array(l);
|
const state = new Uint16Array(l);
|
||||||
|
|
@ -300,7 +300,7 @@ function editHeightmap(options) {
|
||||||
biome[g] = pack.cells.biome[i];
|
biome[g] = pack.cells.biome[i];
|
||||||
culture[g] = pack.cells.culture[i];
|
culture[g] = pack.cells.culture[i];
|
||||||
pop[g] = pack.cells.pop[i];
|
pop[g] = pack.cells.pop[i];
|
||||||
route[g] = pack.cells.route[i];
|
routes[g] = pack.cells.routes[i];
|
||||||
s[g] = pack.cells.s[i];
|
s[g] = pack.cells.s[i];
|
||||||
state[g] = pack.cells.state[i];
|
state[g] = pack.cells.state[i];
|
||||||
province[g] = pack.cells.province[i];
|
province[g] = pack.cells.province[i];
|
||||||
|
|
@ -352,7 +352,7 @@ function editHeightmap(options) {
|
||||||
// assign saved pack data from grid back to pack
|
// assign saved pack data from grid back to pack
|
||||||
const n = pack.cells.i.length;
|
const n = pack.cells.i.length;
|
||||||
pack.cells.pop = new Float32Array(n);
|
pack.cells.pop = new Float32Array(n);
|
||||||
pack.cells.route = new Uint8Array(n);
|
pack.cells.routes = {};
|
||||||
pack.cells.s = new Uint16Array(n);
|
pack.cells.s = new Uint16Array(n);
|
||||||
pack.cells.burg = new Uint16Array(n);
|
pack.cells.burg = new Uint16Array(n);
|
||||||
pack.cells.state = new Uint16Array(n);
|
pack.cells.state = new Uint16Array(n);
|
||||||
|
|
@ -387,7 +387,7 @@ function editHeightmap(options) {
|
||||||
if (!isLand) continue;
|
if (!isLand) continue;
|
||||||
pack.cells.culture[i] = culture[g];
|
pack.cells.culture[i] = culture[g];
|
||||||
pack.cells.pop[i] = pop[g];
|
pack.cells.pop[i] = pop[g];
|
||||||
pack.cells.route[i] = route[g];
|
pack.cells.routes[i] = routes[g];
|
||||||
pack.cells.s[i] = s[g];
|
pack.cells.s[i] = s[g];
|
||||||
pack.cells.state[i] = state[g];
|
pack.cells.state[i] = state[g];
|
||||||
pack.cells.province[i] = province[g];
|
pack.cells.province[i] = province[g];
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,7 @@ class RouteOpisometer extends Measurer {
|
||||||
const cells = pack.cells;
|
const cells = pack.cells;
|
||||||
|
|
||||||
const c = findCell(mousePoint[0], mousePoint[1]);
|
const c = findCell(mousePoint[0], mousePoint[1]);
|
||||||
if (!cells.route[c] && !d3.event.sourceEvent.shiftKey) return;
|
if (!Routes.isConnected(c) && !d3.event.sourceEvent.shiftKey) return;
|
||||||
|
|
||||||
context.trackCell(c, rigth);
|
context.trackCell(c, rigth);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -179,13 +179,15 @@ function editUnits() {
|
||||||
tip("Draw a curve along routes to measure length. Hold Shift to measure away from roads.", true);
|
tip("Draw a curve along routes to measure length. Hold Shift to measure away from roads.", true);
|
||||||
unitsBottom.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed"));
|
unitsBottom.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed"));
|
||||||
this.classList.add("pressed");
|
this.classList.add("pressed");
|
||||||
|
|
||||||
viewbox.style("cursor", "crosshair").call(
|
viewbox.style("cursor", "crosshair").call(
|
||||||
d3.drag().on("start", function () {
|
d3.drag().on("start", function () {
|
||||||
const cells = pack.cells;
|
const cells = pack.cells;
|
||||||
const burgs = pack.burgs;
|
const burgs = pack.burgs;
|
||||||
const point = d3.mouse(this);
|
const point = d3.mouse(this);
|
||||||
const c = findCell(point[0], point[1]);
|
const c = findCell(point[0], point[1]);
|
||||||
if (cells.route[c] || d3.event.sourceEvent.shiftKey) {
|
|
||||||
|
if (Routes.isConnected(c) || d3.event.sourceEvent.shiftKey) {
|
||||||
const b = cells.burg[c];
|
const b = cells.burg[c];
|
||||||
const x = b ? burgs[b].x : cells.p[c][0];
|
const x = b ? burgs[b].x : cells.p[c][0];
|
||||||
const y = b ? burgs[b].y : cells.p[c][1];
|
const y = b ? burgs[b].y : cells.p[c][1];
|
||||||
|
|
@ -194,7 +196,7 @@ function editUnits() {
|
||||||
d3.event.on("drag", function () {
|
d3.event.on("drag", function () {
|
||||||
const point = d3.mouse(this);
|
const point = d3.mouse(this);
|
||||||
const c = findCell(point[0], point[1]);
|
const c = findCell(point[0], point[1]);
|
||||||
if (cells.route[c] || d3.event.sourceEvent.shiftKey) {
|
if (Routes.isConnected(c) || d3.event.sourceEvent.shiftKey) {
|
||||||
routeOpisometer.trackCell(c, true);
|
routeOpisometer.trackCell(c, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue