mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
v. 0.59.07b
This commit is contained in:
parent
f3e36dc455
commit
d0687ed540
2 changed files with 185 additions and 133 deletions
14
index.html
14
index.html
|
|
@ -32,8 +32,8 @@
|
||||||
<script src="libs/quantize.min.js" defer></script>
|
<script src="libs/quantize.min.js" defer></script>
|
||||||
<script src="libs/d3-hexbin.v0.2.min.js" defer></script>
|
<script src="libs/d3-hexbin.v0.2.min.js" defer></script>
|
||||||
<script src="libs/jquery.ui.touch-punch.min.js" defer></script>
|
<script src="libs/jquery.ui.touch-punch.min.js" defer></script>
|
||||||
<link rel="stylesheet" type="text/css" href="index.css?version=0.59.01b"/>
|
<link rel="stylesheet" type="text/css" href="index.css?version=0.59.07b"/>
|
||||||
<link rel="stylesheet" type="text/css" href="icons.css?version=0.59.01b"/>
|
<link rel="stylesheet" type="text/css" href="icons.css?version=0.59.07b"/>
|
||||||
<link rel="stylesheet" type="text/css" href="libs/jquery-ui.css"/>
|
<link rel="stylesheet" type="text/css" href="libs/jquery-ui.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -159,7 +159,7 @@
|
||||||
<div id="loading">
|
<div id="loading">
|
||||||
<div id="title_name">Azgaar's</div>
|
<div id="title_name">Azgaar's</div>
|
||||||
<div id="title">Fantasy Map Generator</div>
|
<div id="title">Fantasy Map Generator</div>
|
||||||
<div id="version">v. 0.58b</div>
|
<div id="version">v. 0.59b</div>
|
||||||
<p id="loading-text">LOADING<span>.</span><span>.</span><span>.</span></p>
|
<p id="loading-text">LOADING<span>.</span><span>.</span><span>.</span></p>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="canvas" style="opacity: 0"></canvas>
|
<canvas id="canvas" style="opacity: 0"></canvas>
|
||||||
|
|
@ -205,8 +205,8 @@
|
||||||
<input id="toggleTooltips" class="checkbox" type="checkbox" checked onclick="$('#tooltip').fadeToggle()">
|
<input id="toggleTooltips" class="checkbox" type="checkbox" checked onclick="$('#tooltip').fadeToggle()">
|
||||||
<label for="toggleTooltips" onmouseover="tip('Toogle tooltip line')" class="checkbox-label">Show tooltips</label>
|
<label for="toggleTooltips" onmouseover="tip('Toogle tooltip line')" class="checkbox-label">Show tooltips</label>
|
||||||
<label id="optionSeedLabel" style="margin-left:10px">Map seed:
|
<label id="optionSeedLabel" style="margin-left:10px">Map seed:
|
||||||
<input id="optionsSeed" class="pureInput" style="width:65px" value="">
|
<input id="optionsSeed" class="pureInput" style="width:50px" value="">
|
||||||
<i onmouseover="tip('Click to generate a map for this seed')" id="optionsSeedGenerate" style="margin-left:-3px" class="icon-play"></i>
|
<i onmouseover="tip('Click to generate a map for this seed')" id="optionsSeedGenerate" style="margin-left:-3px; color: #5d4651" class="icon-play"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -551,7 +551,7 @@
|
||||||
<div id="customizeOptions">
|
<div id="customizeOptions">
|
||||||
<input id="renderOcean" class="checkbox" type="checkbox">
|
<input id="renderOcean" class="checkbox" type="checkbox">
|
||||||
<label for="renderOcean" onmouseover="tip('Render cells below sea level')" class="checkbox-label">Render ocean cells</label>
|
<label for="renderOcean" onmouseover="tip('Render cells below sea level')" class="checkbox-label">Render ocean cells</label>
|
||||||
<input id="changeHeights" class="checkbox" type="checkbox">
|
<input id="changeHeights" class="checkbox" type="checkbox" checked>
|
||||||
<label for="changeHeights" onmouseover="tip('Allow system to change custom heights if reasonable')" class="checkbox-label">Change heights</label>
|
<label for="changeHeights" onmouseover="tip('Allow system to change custom heights if reasonable')" class="checkbox-label">Change heights</label>
|
||||||
</div>
|
</div>
|
||||||
<label onmouseover="tip('Number of Land cells and landmass/ocean ratio')">Landmass:
|
<label onmouseover="tip('Number of Land cells and landmass/ocean ratio')">Landmass:
|
||||||
|
|
@ -1143,5 +1143,5 @@
|
||||||
<input type="file" accept=".txt" id="namesbaseToLoad">
|
<input type="file" accept=".txt" id="namesbaseToLoad">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="script.js?version=0.59.01b"></script>
|
<script src="script.js?version=0.59.07b"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
304
script.js
304
script.js
|
|
@ -75,7 +75,7 @@ function fantasyMap() {
|
||||||
oceanLayers.append("rect").attr("id", "oceanBase");
|
oceanLayers.append("rect").attr("id", "oceanBase");
|
||||||
|
|
||||||
// main data variables
|
// main data variables
|
||||||
var seed, from, voronoi, diagram, polygons, points = [], heights;
|
var seed, params, voronoi, diagram, polygons, points = [], heights;
|
||||||
// Common variables
|
// Common variables
|
||||||
var modules = {}, customization = 0, history = [], historyStage = 0, elSelected, autoResize = true, graphSize,
|
var modules = {}, customization = 0, history = [], historyStage = 0, elSelected, autoResize = true, graphSize,
|
||||||
cells = [], land = [], riversData = [], manors = [], states = [], features = [],
|
cells = [], land = [], riversData = [], manors = [], states = [], features = [],
|
||||||
|
|
@ -226,12 +226,14 @@ function fantasyMap() {
|
||||||
applyNamesData(); // apply default namesbase on load
|
applyNamesData(); // apply default namesbase on load
|
||||||
generate(); // generate map on load
|
generate(); // generate map on load
|
||||||
applyDefaultStyle(); // apply style on load
|
applyDefaultStyle(); // apply style on load
|
||||||
|
focusOn(); // based on searchParams focus on point, cell or burg from MFCG
|
||||||
invokeActiveZooming(); // to hide what need to be hidden
|
invokeActiveZooming(); // to hide what need to be hidden
|
||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
console.group("Random map");
|
console.group("Random map");
|
||||||
console.time("TOTAL");
|
console.time("TOTAL");
|
||||||
applyMapSize();
|
applyMapSize();
|
||||||
|
randomizeOptions();
|
||||||
placePoints();
|
placePoints();
|
||||||
calculateVoronoi(points);
|
calculateVoronoi(points);
|
||||||
detectNeighbors();
|
detectNeighbors();
|
||||||
|
|
@ -242,7 +244,6 @@ function fantasyMap() {
|
||||||
elevateLakes();
|
elevateLakes();
|
||||||
resolveDepressionsPrimary();
|
resolveDepressionsPrimary();
|
||||||
reGraph();
|
reGraph();
|
||||||
randomizeOptions();
|
|
||||||
resolveDepressionsSecondary();
|
resolveDepressionsSecondary();
|
||||||
flux();
|
flux();
|
||||||
addLakes();
|
addLakes();
|
||||||
|
|
@ -250,8 +251,6 @@ function fantasyMap() {
|
||||||
drawRelief();
|
drawRelief();
|
||||||
generateCultures();
|
generateCultures();
|
||||||
manorsAndRegions();
|
manorsAndRegions();
|
||||||
// focus on burg from MFCG
|
|
||||||
if (from === "MFCG") findBurgForMFCG();
|
|
||||||
cleanData();
|
cleanData();
|
||||||
console.timeEnd("TOTAL");
|
console.timeEnd("TOTAL");
|
||||||
console.groupEnd("Random map");
|
console.groupEnd("Random map");
|
||||||
|
|
@ -260,12 +259,11 @@ function fantasyMap() {
|
||||||
// get or generate map seed
|
// get or generate map seed
|
||||||
function getSeed() {
|
function getSeed() {
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const s = url.searchParams.get("seed");
|
params = url.searchParams;
|
||||||
seed = s || Math.floor(Math.random() * 1e9);
|
seed = params.get("seed") || Math.floor(Math.random() * 1e9);
|
||||||
console.log(" seed: " + seed);
|
console.log(" seed: " + seed);
|
||||||
optionsSeed.value = seed;
|
optionsSeed.value = seed;
|
||||||
Math.seedrandom(seed);
|
Math.seedrandom(seed);
|
||||||
from = url.searchParams.get("from");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate new map seed
|
// generate new map seed
|
||||||
|
|
@ -1183,7 +1181,7 @@ function fantasyMap() {
|
||||||
// Mark features (ocean, lakes, islands)
|
// Mark features (ocean, lakes, islands)
|
||||||
function markFeatures() {
|
function markFeatures() {
|
||||||
console.time("markFeatures");
|
console.time("markFeatures");
|
||||||
|
Math.seedrandom(seed); // reset seed to get the same result on heightmap edit
|
||||||
for (let i=0, queue=[0]; queue.length > 0; i++) {
|
for (let i=0, queue=[0]; queue.length > 0; i++) {
|
||||||
const cell = cells[queue[0]];
|
const cell = cells[queue[0]];
|
||||||
cell.fn = i; // feature number
|
cell.fn = i; // feature number
|
||||||
|
|
@ -1316,7 +1314,7 @@ function fantasyMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// recalculate Voronoi Graph to pack cells
|
// recalculate Voronoi Graph to pack cells
|
||||||
function reGraph(noChange) {
|
function reGraph() {
|
||||||
console.time("reGraph");
|
console.time("reGraph");
|
||||||
const tempCells = [], newPoints = []; // to store new data
|
const tempCells = [], newPoints = []; // to store new data
|
||||||
// get average precipitation based on graph size
|
// get average precipitation based on graph size
|
||||||
|
|
@ -1325,18 +1323,17 @@ function fantasyMap() {
|
||||||
let smallLakes = 0;
|
let smallLakes = 0;
|
||||||
const evaporation = 2;
|
const evaporation = 2;
|
||||||
cells.map(function(i, d) {
|
cells.map(function(i, d) {
|
||||||
const height = heights[d];
|
let height = i.height || heights[d];
|
||||||
if (height > 100) console.log(height, d);
|
if (height > 100) height = 100;
|
||||||
const pit = i.pit;
|
const pit = i.pit;
|
||||||
const ctype = i.ctype;
|
const ctype = i.ctype;
|
||||||
if (ctype !== -1 && ctype !== -2 && height < 20) return; // exclude all depp ocean points
|
if (ctype !== -1 && ctype !== -2 && height < 20) return; // exclude all deep ocean points
|
||||||
const x = rn(i.data[0], 1), y = rn(i.data[1], 1);
|
const x = rn(i.data[0], 1), y = rn(i.data[1], 1);
|
||||||
const fn = i.fn;
|
const fn = i.fn;
|
||||||
const harbor = i.harbor;
|
const harbor = i.harbor;
|
||||||
let lake = i.lake;
|
let lake = i.lake;
|
||||||
// mark potential cells for small lakes to add additional point there
|
// mark potential cells for small lakes to add additional point there
|
||||||
// not for custom map if "changeHeights" is not alkowed
|
if (smallLakes < smallLakesMax && !lake && pit > evaporation && ctype !== 2) {
|
||||||
if (!noChange && smallLakes < smallLakesMax && !lake && pit > evaporation && ctype !== 2) {
|
|
||||||
lake = 2;
|
lake = 2;
|
||||||
smallLakes++;
|
smallLakes++;
|
||||||
}
|
}
|
||||||
|
|
@ -1364,7 +1361,6 @@ function fantasyMap() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (lake === 2) { // add potential small lakes
|
if (lake === 2) { // add potential small lakes
|
||||||
//debug.append("circle").attr("r", 0.3).attr("cx", x).attr("cy", y).attr("fill", "blue");
|
|
||||||
polygons[i.index].forEach(function(e) {
|
polygons[i.index].forEach(function(e) {
|
||||||
if (Math.random() > 0.8) return;
|
if (Math.random() > 0.8) return;
|
||||||
let rnd = Math.random() * 0.6 + 0.8;
|
let rnd = Math.random() * 0.6 + 0.8;
|
||||||
|
|
@ -1373,7 +1369,6 @@ function fantasyMap() {
|
||||||
const y1 = rn((e[1] * rnd + i.data[1]) / (1 + rnd), 2);
|
const y1 = rn((e[1] * rnd + i.data[1]) / (1 + rnd), 2);
|
||||||
copy = $.grep(newPoints, function(c) {return x1 === c[0] && y1 === c[1];});
|
copy = $.grep(newPoints, function(c) {return x1 === c[0] && y1 === c[1];});
|
||||||
if (copy.length) return;
|
if (copy.length) return;
|
||||||
//debug.append("circle").attr("r", 0.2).attr("cx", x1).attr("cy", y1).attr("fill", "red");
|
|
||||||
newPoints.push([x1, y1]);
|
newPoints.push([x1, y1]);
|
||||||
tempCells.push({index:tempCells.length, data:[x1, y1], height, pit, ctype, fn, region, culture});
|
tempCells.push({index:tempCells.length, data:[x1, y1], height, pit, ctype, fn, region, culture});
|
||||||
});
|
});
|
||||||
|
|
@ -1508,6 +1503,7 @@ function fantasyMap() {
|
||||||
// Detect and draw the coasline
|
// Detect and draw the coasline
|
||||||
function drawCoastline() {
|
function drawCoastline() {
|
||||||
console.time('drawCoastline');
|
console.time('drawCoastline');
|
||||||
|
Math.seedrandom(seed); // reset seed to get the same result on heightmap edit
|
||||||
const shape = defs.append("mask").attr("id", "shape").attr("fill", "black").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%");
|
const shape = defs.append("mask").attr("id", "shape").attr("fill", "black").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%");
|
||||||
$("#landmass").empty();
|
$("#landmass").empty();
|
||||||
let minX = graphWidth, maxX = 0; // extreme points
|
let minX = graphWidth, maxX = 0; // extreme points
|
||||||
|
|
@ -1533,12 +1529,12 @@ function fantasyMap() {
|
||||||
const x = (land[i].data[0] + cells[ea].data[0]) / 2;
|
const x = (land[i].data[0] + cells[ea].data[0]) / 2;
|
||||||
const y = (land[i].data[1] + cells[ea].data[1]) / 2;
|
const y = (land[i].data[1] + cells[ea].data[1]) / 2;
|
||||||
land[i].haven = ea; // harbor haven (oposite water cell)
|
land[i].haven = ea; // harbor haven (oposite water cell)
|
||||||
land[i].coastX = x, land[i].coastY = y;
|
land[i].coastX = rn(x + (land[i].data[0] - x) * 0.1, 1);
|
||||||
|
land[i].coastY = rn(y + (land[i].data[1] - y) * 0.1, 1);
|
||||||
land[i].data[0] = rn(x + (land[i].data[0] - x) * 0.5, 1);
|
land[i].data[0] = rn(x + (land[i].data[0] - x) * 0.5, 1);
|
||||||
land[i].data[1] = rn(y + (land[i].data[1] - y) * 0.5, 1);
|
land[i].data[1] = rn(y + (land[i].data[1] - y) * 0.5, 1);
|
||||||
}
|
}
|
||||||
if (features[cells[ea].fn].border) {
|
if (features[cells[ea].fn].border) {
|
||||||
//debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "blue").attr("stroke-width", .2);
|
|
||||||
oceanEdges[f].push({start, end});
|
oceanEdges[f].push({start, end});
|
||||||
// island extreme points
|
// island extreme points
|
||||||
if (edge[0][0] < minX) {minX = edge[0][0]; minXedge = edge[0]}
|
if (edge[0][0] < minX) {minX = edge[0][0]; minXedge = edge[0]}
|
||||||
|
|
@ -1549,12 +1545,10 @@ function fantasyMap() {
|
||||||
const l = cells[ea].fn;
|
const l = cells[ea].fn;
|
||||||
if (!lakeEdges[f][l]) lakeEdges[f][l] = [];
|
if (!lakeEdges[f][l]) lakeEdges[f][l] = [];
|
||||||
lakeEdges[f][l].push({start, end});
|
lakeEdges[f][l].push({start, end});
|
||||||
//debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "red").attr("stroke-width", .2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
oceanEdges[f].push({start, end});
|
oceanEdges[f].push({start, end});
|
||||||
//debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "black").attr("stroke-width", .5);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1842,12 +1836,16 @@ function fantasyMap() {
|
||||||
function elevateLakes() {
|
function elevateLakes() {
|
||||||
console.time('elevateLakes');
|
console.time('elevateLakes');
|
||||||
const lakes = $.grep(cells, function(e, d) {return heights[d] < 20 && !features[e.fn].border;});
|
const lakes = $.grep(cells, function(e, d) {return heights[d] < 20 && !features[e.fn].border;});
|
||||||
lakes.sort(function(a, b) {return b.height - a.height;});
|
lakes.sort(function(a, b) {return heights[b.index] - heights[a.index];});
|
||||||
for (let i=0; i < lakes.length; i++) {
|
for (let i=0; i < lakes.length; i++) {
|
||||||
const hs = [], id = lakes[i].index;
|
const hs = [], id = lakes[i].index;
|
||||||
lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 20) hs.push(cells[n].height)});
|
cells[id].height = heights[id]; // use height on object level
|
||||||
if (hs.length) heights[id] = d3.min(hs) - 1;
|
lakes[i].neighbors.forEach(function(n) {
|
||||||
if (heights[id] < 20) heights[id] = 20;
|
const nHeight = cells[n].height || heights[n];
|
||||||
|
if (nHeight >= 20) hs.push(nHeight);
|
||||||
|
});
|
||||||
|
if (hs.length) cells[id].height = d3.min(hs) - 1;
|
||||||
|
if (cells[id].height < 20) cells[id].height = 20;
|
||||||
lakes[i].lake = 1;
|
lakes[i].lake = 1;
|
||||||
}
|
}
|
||||||
console.timeEnd('elevateLakes');
|
console.timeEnd('elevateLakes');
|
||||||
|
|
@ -1856,20 +1854,23 @@ function fantasyMap() {
|
||||||
// Depression filling algorithm (for a correct water flux modeling; phase1)
|
// Depression filling algorithm (for a correct water flux modeling; phase1)
|
||||||
function resolveDepressionsPrimary() {
|
function resolveDepressionsPrimary() {
|
||||||
console.time('resolveDepressionsPrimary');
|
console.time('resolveDepressionsPrimary');
|
||||||
land = $.grep(cells, function(e, d) {return heights[d] >= 20;});
|
land = $.grep(cells, function(e, d) {
|
||||||
land.sort(function(a, b) {return heights[b.index] - heights[a.index];});
|
if (!e.height) e.height = heights[d]; // use height on object level
|
||||||
|
return e.height >= 20;
|
||||||
|
});
|
||||||
|
land.sort(function(a, b) {return b.height - a.height;});
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
for (let l = 0, depression = 1; depression > 0 && l < limit; l++) {
|
for (let l = 0, depression = 1; depression > 0 && l < limit; l++) {
|
||||||
depression = 0;
|
depression = 0;
|
||||||
for (let i = 0; i < land.length; i++) {
|
for (let i = 0; i < land.length; i++) {
|
||||||
const id = land[i].index;
|
const id = land[i].index;
|
||||||
if (land[i].type === "border") continue;
|
if (land[i].type === "border") continue;
|
||||||
const hs = land[i].neighbors.map(function(n) {return heights[n];});
|
const hs = land[i].neighbors.map(function(n) {return cells[n].height;});
|
||||||
const minHigh = d3.min(hs);
|
const minHigh = d3.min(hs);
|
||||||
if (heights[id] <= minHigh) {
|
if (cells[id].height <= minHigh) {
|
||||||
depression++;
|
depression++;
|
||||||
land[i].pit = land[i].pit ? land[i].pit + 1 : 1;
|
land[i].pit = land[i].pit ? land[i].pit + 1 : 1;
|
||||||
heights[id] = minHigh + 2;
|
cells[id].height = minHigh + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (l === 0) console.log(" depressions init: " + depression);
|
if (l === 0) console.log(" depressions init: " + depression);
|
||||||
|
|
@ -1887,8 +1888,8 @@ function fantasyMap() {
|
||||||
depression = 0;
|
depression = 0;
|
||||||
for (let i = 0; i < land.length; i++) {
|
for (let i = 0; i < land.length; i++) {
|
||||||
if (land[i].ctype === 99) continue;
|
if (land[i].ctype === 99) continue;
|
||||||
const heights = land[i].neighbors.map(function(n) {return cells[n].height});
|
const nHeights = land[i].neighbors.map(function(n) {return cells[n].height});
|
||||||
const minHigh = d3.min(heights);
|
const minHigh = d3.min(nHeights);
|
||||||
if (land[i].height <= minHigh) {
|
if (land[i].height <= minHigh) {
|
||||||
depression++;
|
depression++;
|
||||||
land[i].pit = land[i].pit ? land[i].pit + 1 : 1;
|
land[i].pit = land[i].pit ? land[i].pit + 1 : 1;
|
||||||
|
|
@ -1901,12 +1902,12 @@ function fantasyMap() {
|
||||||
console.timeEnd('resolveDepressionsSecondary');
|
console.timeEnd('resolveDepressionsSecondary');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore initial heights if user don't want system to change heightmap
|
||||||
function restoreCustomHeights() {
|
function restoreCustomHeights() {
|
||||||
land.forEach(function(l) {
|
land.forEach(function(l) {
|
||||||
if (l.pit) {
|
if (!l.pit) return;
|
||||||
l.height = Math.trunc(l.height - l.pit * 2);
|
l.height = Math.trunc(l.height - l.pit * 2);
|
||||||
if (l.height < 20) l.height = 20;
|
if (l.height < 20) l.height = 20;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2507,7 +2508,7 @@ function fantasyMap() {
|
||||||
land.map(function(l) {
|
land.map(function(l) {
|
||||||
if (l.river === river) {
|
if (l.river === river) {
|
||||||
l.river = undefined;
|
l.river = undefined;
|
||||||
i.flux = avPrec;
|
l.flux = avPrec;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
elSelected.remove();
|
elSelected.remove();
|
||||||
|
|
@ -3716,7 +3717,7 @@ function fantasyMap() {
|
||||||
y = cell.coastY;
|
y = cell.coastY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cell.river) {
|
if (cell.river && cell.type !== 1) {
|
||||||
let shift = 0.2 * cell.flux;
|
let shift = 0.2 * cell.flux;
|
||||||
if (shift < 0.2) shift = 0.2;
|
if (shift < 0.2) shift = 0.2;
|
||||||
if (shift > 1) shift = 1;
|
if (shift > 1) shift = 1;
|
||||||
|
|
@ -4659,32 +4660,55 @@ function fantasyMap() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// focus on coorditanes, cell or burg provided in searchParams
|
||||||
|
function focusOn() {
|
||||||
|
if (params.get("from") === "MFCG") {
|
||||||
|
// focus on burg from MFCG
|
||||||
|
findBurgForMFCG();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let s = params.get("scale") || 8;
|
||||||
|
let x = params.get("x");
|
||||||
|
let y = params.get("y");
|
||||||
|
let c = params.get("cell");
|
||||||
|
if (c !== null) {
|
||||||
|
x = cells[+c].data[0];
|
||||||
|
y = cells[+c].data[1];
|
||||||
|
}
|
||||||
|
let b = params.get("burg");
|
||||||
|
if (b !== null) {
|
||||||
|
x = manors[+b].x;
|
||||||
|
y = manors[+b].y;
|
||||||
|
}
|
||||||
|
if (x !== null && y !== null) zoomTo(x, y, s, 1600);
|
||||||
|
}
|
||||||
|
|
||||||
// find burg from MFCG and focus on it
|
// find burg from MFCG and focus on it
|
||||||
function findBurgForMFCG() {
|
function findBurgForMFCG() {
|
||||||
if (!manors.length) {console.error("No burgs generated. Cannot select a burg for MFCG"); return;}
|
if (!manors.length) {console.error("No burgs generated. Cannot select a burg for MFCG"); return;}
|
||||||
const url = new URL(window.location.href);
|
const size = +params.get("size");
|
||||||
const size = +url.searchParams.get("size");
|
let coast = +params.get("coast");
|
||||||
let coast = +url.searchParams.get("coast");
|
let port = +params.get("port");
|
||||||
let river = +url.searchParams.get("river");
|
let river = +params.get("river");
|
||||||
let selection = defineSelection(coast, river);
|
let selection = defineSelection(coast, port, river);
|
||||||
if (!selection.length) selection = defineSelection(coast, !river);
|
if (!selection.length) selection = defineSelection(coast, !port, !river);
|
||||||
if (!selection.length) selection = defineSelection(!coast, !river);
|
if (!selection.length) selection = defineSelection(!coast, 0, !river);
|
||||||
|
if (!selection.length) selection = manors[0]; // select first if nothing is found
|
||||||
if (!selection.length) {console.error("Cannot find a burg for MFCG"); return;}
|
if (!selection.length) {console.error("Cannot find a burg for MFCG"); return;}
|
||||||
|
|
||||||
function defineSelection(coast, river) {
|
function defineSelection(coast, port, river) {
|
||||||
let selection = [];
|
let selection = [];
|
||||||
if (coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].port !== undefined && cells[e.cell].river !== undefined;});
|
if (port && river) selection = $.grep(manors, function(e) {return cells[e.cell].port !== undefined && cells[e.cell].river !== undefined;});
|
||||||
if (!coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].port === undefined && cells[e.cell].river === undefined;});
|
else if (!port && coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].port === undefined && cells[e.cell].ctype === 1 && cells[e.cell].river !== undefined;});
|
||||||
if (!coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].port === undefined && cells[e.cell].river !== undefined;});
|
else if (!coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].ctype !== 1 && cells[e.cell].river === undefined;});
|
||||||
if (coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].port !== undefined && cells[e.cell].river === undefined;});
|
else if (!coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].ctype !== 1 && cells[e.cell].river !== undefined;});
|
||||||
|
else if (coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].ctype === 1 && cells[e.cell].river === undefined;});
|
||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
// select a burg with closes population from selection
|
// select a burg with closes population from selection
|
||||||
const selected = d3.scan(selection, function(a, b) {return Math.abs(a.population - size) - Math.abs(b.population - size);});
|
const selected = d3.scan(selection, function(a, b) {return Math.abs(a.population - size) - Math.abs(b.population - size);});
|
||||||
console.log(selection)
|
|
||||||
const burg = selection[selected].i;
|
const burg = selection[selected].i;
|
||||||
console.log(selected, size)
|
|
||||||
if (size && burg !== undefined) {manors[burg].population = size;} else {return;}
|
if (size && burg !== undefined) {manors[burg].population = size;} else {return;}
|
||||||
|
|
||||||
// focus on found burg
|
// focus on found burg
|
||||||
|
|
@ -4714,8 +4738,8 @@ function fantasyMap() {
|
||||||
let height = i.height;
|
let height = i.height;
|
||||||
if (height < 20 && !i.lake) return;
|
if (height < 20 && !i.lake) return;
|
||||||
if (i.lake) {
|
if (i.lake) {
|
||||||
const heights = i.neighbors.map(function(e) {if (cells[e].height >= 20) return cells[e].height;})
|
const nHeights = i.neighbors.map(function(e) {if (cells[e].height >= 20) return cells[e].height;})
|
||||||
const mean = d3.mean(heights);
|
const mean = d3.mean(nHeights);
|
||||||
if (!mean) return;
|
if (!mean) return;
|
||||||
height = Math.trunc(mean);
|
height = Math.trunc(mean);
|
||||||
if (height < 20 || isNaN(height)) height = 20;
|
if (height < 20 || isNaN(height)) height = 20;
|
||||||
|
|
@ -5051,12 +5075,11 @@ function fantasyMap() {
|
||||||
drawOcean();
|
drawOcean();
|
||||||
elevateLakes();
|
elevateLakes();
|
||||||
resolveDepressionsPrimary();
|
resolveDepressionsPrimary();
|
||||||
const noChange = !changeHeights.checked;
|
reGraph();
|
||||||
reGraph(noChange);
|
|
||||||
resolveDepressionsSecondary();
|
resolveDepressionsSecondary();
|
||||||
flux();
|
flux();
|
||||||
addLakes();
|
addLakes();
|
||||||
if (noChange) restoreCustomHeights();
|
if (!changeHeights.checked) restoreCustomHeights();
|
||||||
drawCoastline();
|
drawCoastline();
|
||||||
drawRelief();
|
drawRelief();
|
||||||
const keepData = states.length && manors.length;
|
const keepData = states.length && manors.length;
|
||||||
|
|
@ -5215,9 +5238,9 @@ function fantasyMap() {
|
||||||
cell.river = river;
|
cell.river = river;
|
||||||
var x = cell.data[0], y = cell.data[1];
|
var x = cell.data[0], y = cell.data[1];
|
||||||
dataRiver.push({x, y, cell:index});
|
dataRiver.push({x, y, cell:index});
|
||||||
var heights = [];
|
var nHeights = [];
|
||||||
cell.neighbors.forEach(function(e) {heights.push(cells[e].height);});
|
cell.neighbors.forEach(function(e) {nHeights.push(cells[e].height);});
|
||||||
var minId = heights.indexOf(d3.min(heights));
|
var minId = nHeights.indexOf(d3.min(nHeights));
|
||||||
var min = cell.neighbors[minId];
|
var min = cell.neighbors[minId];
|
||||||
var tx = cells[min].data[0], ty = cells[min].data[1];
|
var tx = cells[min].data[0], ty = cells[min].data[1];
|
||||||
if (cells[min].height < 20) {
|
if (cells[min].height < 20) {
|
||||||
|
|
@ -5648,8 +5671,8 @@ function fantasyMap() {
|
||||||
if (editGroupInput.value !== "") {
|
if (editGroupInput.value !== "") {
|
||||||
groupNew = editGroupInput.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
groupNew = editGroupInput.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
||||||
if (Number.isFinite(+groupNew.charAt(0))) groupNew = "g" + groupNew;
|
if (Number.isFinite(+groupNew.charAt(0))) groupNew = "g" + groupNew;
|
||||||
if (groupNew === "towns") groupNew = "town_labels";
|
const size = svg.selectAll("#"+groupNew).size();
|
||||||
if (groupNew === "capitals") groupNew = "capital_labels";
|
if (size) groupNew += size; // if el with this id exists, add size to id;
|
||||||
}
|
}
|
||||||
if (groupOld !== groupNew) {
|
if (groupOld !== groupNew) {
|
||||||
var removed = elSelected.remove();
|
var removed = elSelected.remove();
|
||||||
|
|
@ -5734,11 +5757,13 @@ function fantasyMap() {
|
||||||
// downalod map as SVG or PNG file
|
// downalod map as SVG or PNG file
|
||||||
function saveAsImage(type) {
|
function saveAsImage(type) {
|
||||||
console.time("saveAsImage");
|
console.time("saveAsImage");
|
||||||
// get all used fonts
|
const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"];
|
||||||
|
// get non-standard fonts used for labels to fetch them from web
|
||||||
const fontsInUse = []; // to store fonts currently in use
|
const fontsInUse = []; // to store fonts currently in use
|
||||||
labels.selectAll("g").each(function(d) {
|
labels.selectAll("g").each(function(d) {
|
||||||
const font = d3.select(this).attr("data-font");
|
const font = d3.select(this).attr("data-font");
|
||||||
if (!font) return;
|
if (!font) return;
|
||||||
|
if (webSafe.indexOf(font) !== -1) return; // do not fetch web-safe fonts
|
||||||
if (fontsInUse.indexOf(font) === -1) fontsInUse.push(font);
|
if (fontsInUse.indexOf(font) === -1) fontsInUse.push(font);
|
||||||
});
|
});
|
||||||
const fontsToLoad = "https://fonts.googleapis.com/css?family=" + fontsInUse.join("|");
|
const fontsToLoad = "https://fonts.googleapis.com/css?family=" + fontsInUse.join("|");
|
||||||
|
|
@ -5904,10 +5929,14 @@ function fantasyMap() {
|
||||||
// Save in .map format, based on FileSystem API
|
// Save in .map format, based on FileSystem API
|
||||||
function saveMap() {
|
function saveMap() {
|
||||||
console.time("saveMap");
|
console.time("saveMap");
|
||||||
// data convention: 0 - version; 1 - all points; 2 - cells; 3 - manors; 4 - states;
|
// data convention: 0 - params; 1 - all points; 2 - cells; 3 - manors; 4 - states;
|
||||||
// 5 - svg; 6 - options (see below); 7 - cultures;
|
// 5 - svg; 6 - options (see below); 7 - cultures;
|
||||||
// 8 - empty (former nameBase); 9 - empty (former nameBases); 10 - heights;
|
// 8 - empty (former nameBase); 9 - empty (former nameBases); 10 - heights;
|
||||||
// size stats: points = 6%, cells = 36%, manors and states = 2%, svg = 56%;
|
// size stats: points = 6%, cells = 36%, manors and states = 2%, svg = 56%;
|
||||||
|
const date = new Date();
|
||||||
|
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
|
||||||
|
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
|
||||||
|
const params = version + "|" + license + "|" + dateString + "|" + seed;
|
||||||
const options = customization + "|" +
|
const options = customization + "|" +
|
||||||
distanceUnit.value + "|" + distanceScale.value + "|" + areaUnit.value + "|" +
|
distanceUnit.value + "|" + distanceScale.value + "|" + areaUnit.value + "|" +
|
||||||
barSize.value + "|" + barLabel.value + "|" + barBackOpacity.value + "|" + barBackColor.value + "|" +
|
barSize.value + "|" + barLabel.value + "|" + barBackOpacity.value + "|" + barBackColor.value + "|" +
|
||||||
|
|
@ -5923,7 +5952,7 @@ function fantasyMap() {
|
||||||
|
|
||||||
var svg_xml = (new XMLSerializer()).serializeToString(svg.node());
|
var svg_xml = (new XMLSerializer()).serializeToString(svg.node());
|
||||||
var line = "\r\n";
|
var line = "\r\n";
|
||||||
var data = version + line + JSON.stringify(points) + line + JSON.stringify(cells) + line;
|
var data = params + line + JSON.stringify(points) + line + JSON.stringify(cells) + line;
|
||||||
data += JSON.stringify(manors) + line + JSON.stringify(states) + line + svg_xml + line + options + line;
|
data += JSON.stringify(manors) + line + JSON.stringify(states) + line + svg_xml + line + options + line;
|
||||||
data += JSON.stringify(cultures) + line + "" + line + "" + line + heights + line;
|
data += JSON.stringify(cultures) + line + "" + line + "" + line + heights + line;
|
||||||
var dataBlob = new Blob([data], {type:"text/plain"});
|
var dataBlob = new Blob([data], {type:"text/plain"});
|
||||||
|
|
@ -5958,9 +5987,10 @@ function fantasyMap() {
|
||||||
fileReader.onload = function(fileLoadedEvent) {
|
fileReader.onload = function(fileLoadedEvent) {
|
||||||
var dataLoaded = fileLoadedEvent.target.result;
|
var dataLoaded = fileLoadedEvent.target.result;
|
||||||
var data = dataLoaded.split("\r\n");
|
var data = dataLoaded.split("\r\n");
|
||||||
// data convention: 0 - version; 1 - all points; 2 - cells; 3 - manors; 4 - states;
|
// data convention: 0 - params; 1 - all points; 2 - cells; 3 - manors; 4 - states;
|
||||||
// 5 - svg; 6 - options; 7 - cultures; 8 - none; 9 - none; 10 - heights;
|
// 5 - svg; 6 - options; 7 - cultures; 8 - none; 9 - none; 10 - heights;
|
||||||
var mapVersion = data[0];
|
const params = data[0].split("|");
|
||||||
|
const mapVersion = params[0] || data[0];
|
||||||
if (mapVersion !== version) {
|
if (mapVersion !== version) {
|
||||||
var message = `The Map version `;
|
var message = `The Map version `;
|
||||||
// mapVersion reference was not added to downloaded map before v. 0.52b, so I cannot support really old files
|
// mapVersion reference was not added to downloaded map before v. 0.52b, so I cannot support really old files
|
||||||
|
|
@ -5971,7 +6001,7 @@ function fantasyMap() {
|
||||||
or just keep using
|
or just keep using
|
||||||
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">an appropriate version</a>
|
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">an appropriate version</a>
|
||||||
of the Generator`;
|
of the Generator`;
|
||||||
} else {
|
} else if (!mapVersion || parseFloat(mapVersion) < 0.54) {
|
||||||
message += `you are trying to load is too old and cannot be updated. Please re-create the map or just keep using
|
message += `you are trying to load is too old and cannot be updated. Please re-create the map or just keep using
|
||||||
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">an archived version</a>
|
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">an archived version</a>
|
||||||
of the Generator. Please note the Gennerator is still on demo and a lot of crusial changes are being made every month`;
|
of the Generator. Please note the Gennerator is still on demo and a lot of crusial changes are being made every month`;
|
||||||
|
|
@ -5989,6 +6019,13 @@ function fantasyMap() {
|
||||||
|
|
||||||
function loadDataFromMap(data) {
|
function loadDataFromMap(data) {
|
||||||
closeDialogs();
|
closeDialogs();
|
||||||
|
// update seed
|
||||||
|
const params = data[0].split("|");
|
||||||
|
if (params[3]) {
|
||||||
|
seed = params[3];
|
||||||
|
optionsSeed.value = seed;
|
||||||
|
}
|
||||||
|
|
||||||
// get options
|
// get options
|
||||||
if (data[0] === "0.52b" || data[0] === "0.53b") {
|
if (data[0] === "0.52b" || data[0] === "0.53b") {
|
||||||
customization = 0;
|
customization = 0;
|
||||||
|
|
@ -6161,6 +6198,68 @@ function fantasyMap() {
|
||||||
// update data
|
// update data
|
||||||
newPoints = [], riversData = [], queue = [], elSelected = "";
|
newPoints = [], riversData = [], queue = [], elSelected = "";
|
||||||
points = JSON.parse(data[1]);
|
points = JSON.parse(data[1]);
|
||||||
|
cells = JSON.parse(data[2]);
|
||||||
|
manors = JSON.parse(data[3]);
|
||||||
|
if (data[7]) cultures = JSON.parse(data[7]);
|
||||||
|
if (data[7] === undefined) generateCultures();
|
||||||
|
|
||||||
|
// place random point
|
||||||
|
function placePoint() {
|
||||||
|
const x = Math.floor(Math.random() * graphWidth * 0.8 + graphWidth * 0.1);
|
||||||
|
const y = Math.floor(Math.random() * graphHeight * 0.8 + graphHeight * 0.1);
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure each culure has a valid namesbase assigned, if not assign first base
|
||||||
|
if (!nameBase[0]) applyDefaultNamesData();
|
||||||
|
cultures.forEach(function(c) {
|
||||||
|
const b = c.base;
|
||||||
|
if (b === undefined) c.base = 0;
|
||||||
|
if (!nameBase[b] || !nameBases[b]) c.base = 0;
|
||||||
|
if (c.center === undefined) c.center = placePoint();
|
||||||
|
});
|
||||||
|
const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize
|
||||||
|
|
||||||
|
// cells validations
|
||||||
|
cells.forEach(function(c, d) {
|
||||||
|
// collect points
|
||||||
|
newPoints.push(c.data);
|
||||||
|
|
||||||
|
// update old 0-1 height range to a new 0-100 range
|
||||||
|
if (c.height < 1) c.height = Math.trunc(c.height * 100);
|
||||||
|
if (c.height === 1 && c.region !== undefined && c.flux !== undefined) c.height = 100;
|
||||||
|
|
||||||
|
// check if there are any unavailable cultures
|
||||||
|
if (c.culture > cultures.length - 1) {
|
||||||
|
const center = [c.data[0], c.data[1]];
|
||||||
|
const cult = {name:"AUTO_"+c.culture, color:"#ff0000", base:0, center};
|
||||||
|
cultures.push(cult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.height >= 20) {
|
||||||
|
if (!polygons[d] || !polygons[d].length) return;
|
||||||
|
// calculate area
|
||||||
|
if (c.area === undefined || isNaN(c.area)) {
|
||||||
|
const area = d3.polygonArea(polygons[d]);
|
||||||
|
c.area = rn(Math.abs(area), 2);
|
||||||
|
}
|
||||||
|
// calculate population
|
||||||
|
if (c.pop === undefined || isNaN(c.pop)) {
|
||||||
|
let population = 0;
|
||||||
|
const elevationFactor = Math.pow((100 - c.height) / 100, 3);
|
||||||
|
population = elevationFactor * c.area * graphSizeAdj;
|
||||||
|
if (c.region === "neutral") population *= 0.5;
|
||||||
|
c.pop = rn(population, 1);
|
||||||
|
}
|
||||||
|
// if culture is undefined, set to 0
|
||||||
|
if (c.culture === undefined || isNaN(c.culture)) c.culture = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
land = $.grep(cells, function(e) {return (e.height >= 20);});
|
||||||
|
calculateVoronoi(newPoints);
|
||||||
|
|
||||||
|
// get heights Uint8Array
|
||||||
if (data[10]) {heights = new Uint8Array(data[10].split(","));}
|
if (data[10]) {heights = new Uint8Array(data[10].split(","));}
|
||||||
else {
|
else {
|
||||||
heights = new Uint8Array(points.length);
|
heights = new Uint8Array(points.length);
|
||||||
|
|
@ -6169,52 +6268,6 @@ function fantasyMap() {
|
||||||
heights[i] = cells[cell].height;
|
heights[i] = cells[cell].height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cells = JSON.parse(data[2]);
|
|
||||||
|
|
||||||
manors = JSON.parse(data[3]);
|
|
||||||
if (data[7]) cultures = JSON.parse(data[7]);
|
|
||||||
if (data[7] === undefined) generateCultures();
|
|
||||||
|
|
||||||
// ensure each culure has a valid namesbase assigned, if not assign first base
|
|
||||||
if (!nameBase[0]) applyDefaultNamesData();
|
|
||||||
cultures.forEach(function(c) {
|
|
||||||
const b = c.base;
|
|
||||||
if (b === undefined) c.base = 0;
|
|
||||||
if (!nameBase[b] || !nameBases[b]) c.base = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
// cells validations
|
|
||||||
cells.forEach(function(c) {
|
|
||||||
// collect points
|
|
||||||
newPoints.push(c.data);
|
|
||||||
|
|
||||||
// update old 0-1 height range to new 0-100 range
|
|
||||||
if (c.height > 1) return;
|
|
||||||
if (c.height === 1 && c.region === undefined && c.flux === undefined) return;
|
|
||||||
c.height = Math.trunc(c.height * 100);
|
|
||||||
|
|
||||||
// check if there unavailable cultures
|
|
||||||
if (c.culture > cultures.length - 1) cultures.push({name:"AUTO_"+c.culture, color:"#ff0000", base:0});
|
|
||||||
});
|
|
||||||
|
|
||||||
land = $.grep(cells, function(e) {return (e.height >= 20);});
|
|
||||||
calculateVoronoi(newPoints);
|
|
||||||
|
|
||||||
// calculate areas / population for old maps
|
|
||||||
const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize
|
|
||||||
land.forEach(function(i) {
|
|
||||||
const p = i.index;
|
|
||||||
if (!polygons[p] || !polygons[p].length) return;
|
|
||||||
const area = d3.polygonArea(polygons[p]);
|
|
||||||
i.area = rn(Math.abs(area), 2);
|
|
||||||
if (i.pop === undefined) {
|
|
||||||
let population = 0;
|
|
||||||
const elevationFactor = Math.pow((100 - i.height) / 100, 3);
|
|
||||||
population = elevationFactor * i.area * graphSizeAdj;
|
|
||||||
if (i.region === "neutral") population *= 0.5;
|
|
||||||
i.pop = rn(population, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// restore Heightmap customization mode
|
// restore Heightmap customization mode
|
||||||
if (customization === 1) {
|
if (customization === 1) {
|
||||||
|
|
@ -6751,11 +6804,11 @@ function fantasyMap() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (id === "fromHeightmap") {
|
if (id === "fromHeightmap") {
|
||||||
const message = `Hightmap is a basic element on which secondary data (burgs, countries, cultures) is based.
|
const message = `Hightmap is a basic element on which secondary data (rivers, burgs, countries etc) is based.
|
||||||
If you want to significantly change the hightmap, it may be better to clean up all the secondary data
|
If you want to significantly change the hightmap, it may be better to clean up all the secondary data
|
||||||
and let the system to re-generate it based on the updated hightmap. In case of minor changes, you can keep the data.
|
and let the system to re-generate it based on the updated hightmap. In case of minor changes, you can keep the data.
|
||||||
Newly added lands will be considered as neutral. Burgs located on a removed land cells will be deleted.
|
Newly added lands will be considered as neutral. Burgs located on a removed land cells will be deleted.
|
||||||
Routes won't be regenerated.`
|
Rivers and small lakes will be re-gerenated based on updated heightmap. Routes won't be regenerated.`
|
||||||
alertMessage.innerHTML = message;
|
alertMessage.innerHTML = message;
|
||||||
$("#alert").dialog({resizable: false, title: "Edit Heightmap",
|
$("#alert").dialog({resizable: false, title: "Edit Heightmap",
|
||||||
buttons: {
|
buttons: {
|
||||||
|
|
@ -6977,7 +7030,11 @@ function fantasyMap() {
|
||||||
const regionData = [], cultureData = [];
|
const regionData = [], cultureData = [];
|
||||||
if (type !== "clean") {
|
if (type !== "clean") {
|
||||||
for (let i = 0; i < points.length; i++) {
|
for (let i = 0; i < points.length; i++) {
|
||||||
const cell = diagram.find(points[i][0], points[i][1]).index;
|
let cell = diagram.find(points[i][0], points[i][1]).index;
|
||||||
|
// if closest cell is a small lake, try to find a land neighbor
|
||||||
|
if (cells[cell].lake === 2) cells[cell].neighbors.forEach(function(n) {
|
||||||
|
if (cells[n].height >= 20) {cell = n; return;}
|
||||||
|
});
|
||||||
let region = cells[cell].region;
|
let region = cells[cell].region;
|
||||||
if (region === undefined) region = -1;
|
if (region === undefined) region = -1;
|
||||||
regionData.push(region);
|
regionData.push(region);
|
||||||
|
|
@ -8654,7 +8711,7 @@ function fantasyMap() {
|
||||||
drawRegions();
|
drawRegions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore keeped region data on edit heightmap completion
|
// restore keeped region / burgs / cultures data on edit heightmap completion
|
||||||
function restoreRegions() {
|
function restoreRegions() {
|
||||||
borders.selectAll("path").remove();
|
borders.selectAll("path").remove();
|
||||||
labels.select("#countries").selectAll("text").remove();
|
labels.select("#countries").selectAll("text").remove();
|
||||||
|
|
@ -8664,8 +8721,7 @@ function fantasyMap() {
|
||||||
// remove manor in ocean
|
// remove manor in ocean
|
||||||
m.region = "removed";
|
m.region = "removed";
|
||||||
m.cell = cell;
|
m.cell = cell;
|
||||||
labels.select("[data-id='" + m.i + "']").remove();
|
d3.selectAll("[data-id='" + m.i + "']").remove();
|
||||||
icons.select("[data-id='" + m.i + "']").remove();
|
|
||||||
} else {
|
} else {
|
||||||
m.cell = cell;
|
m.cell = cell;
|
||||||
cells[cell].manor = m.i;
|
cells[cell].manor = m.i;
|
||||||
|
|
@ -9294,16 +9350,12 @@ function fantasyMap() {
|
||||||
if (id === "aboutTab") {$("#aboutContent").show();}
|
if (id === "aboutTab") {$("#aboutContent").show();}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Generate map from provided seed
|
// re-load page with provided seed
|
||||||
$("#optionsSeedGenerate").on("click", function() {
|
$("#optionsSeedGenerate").on("click", function() {
|
||||||
if (optionsSeed.value == seed) return;
|
if (optionsSeed.value == seed) return;
|
||||||
seed = optionsSeed.value;
|
seed = optionsSeed.value;
|
||||||
console.log(" seed: " + seed);
|
const url = new URL(window.location.href);
|
||||||
Math.seedrandom(seed);
|
window.location.href = url.pathname + "?seed=" + seed;
|
||||||
exitCustomization();
|
|
||||||
undraw();
|
|
||||||
resetZoom(1000);
|
|
||||||
generate();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pull request from @evyatron
|
// Pull request from @evyatron
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue