v. 0.58.02b

This commit is contained in:
Azgaar 2018-08-02 00:59:48 +03:00
parent 93cadafa27
commit 22fd48eabd
3 changed files with 145 additions and 117 deletions

View file

@ -59,8 +59,7 @@ button, select, a {
} }
#landmass { #landmass {
fill-rule: evenodd; mask: url(#shape);
stroke: none;
} }
#lakes, #lakes,

View file

@ -13,11 +13,11 @@
<title>Azgaar's Fantasy Map Generator</title> <title>Azgaar's Fantasy Map Generator</title>
<meta name="application-name" content="Azgaar's Fantasy Map Generator"> <meta name="application-name" content="Azgaar's Fantasy Map Generator">
<meta name="author" content="Azgaar (Max Ganiev)"> <meta name="author" content="Azgaar (Max Ganiev)">
<meta name="description" content="Azgaar's Fantasy Map Generator (demo). Based on D3 Voronoi diagram rendered to svg"> <meta name="description" content="Azgaar's Fantasy Map Generator and Editor">
<meta name="google" content="notranslate"> <meta name="google" content="notranslate">
<meta property="og:url" content="https://azgaar.github.io/Fantasy-Map-Generator/"> <meta property="og:url" content="https://azgaar.github.io/Fantasy-Map-Generator/">
<meta property="og:title" content="Azgaar's Fantasy Map Generator"> <meta property="og:title" content="Azgaar's Fantasy Map Generator">
<meta property="og:description" content="Demo version. Based on D3 Voronoi diagram rendered to svg"> <meta property="og:description" content="Based on Voronoi diagram rendered to svg">
<meta property="og:image" content="images/preview.png"> <meta property="og:image" content="images/preview.png">
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32"/> <link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32"/>
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16"/> <link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16"/>
@ -31,64 +31,66 @@
<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.58.00b"/> <link rel="stylesheet" type="text/css" href="index.css?version=0.58.02b"/>
<link rel="stylesheet" type="text/css" href="icons.css?version=0.58.00b"/> <link rel="stylesheet" type="text/css" href="icons.css?version=0.58.02b"/>
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/> <link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/>
</head> </head>
<body> <body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
<defs> <defs>
<filter id="blurFilter" x="-1" y="-1" width="100" height="100"> <g id="filters">
<feGaussianBlur in="SourceGraphic" stdDeviation="0.2"/> <filter id="blurFilter" x="-1" y="-1" width="100" height="100">
</filter> <feGaussianBlur in="SourceGraphic" stdDeviation="0.2"/>
<filter id="blur1" x="-1" y="-1" width="100" height="100"> </filter>
<feGaussianBlur in="SourceGraphic" stdDeviation="1"/> <filter id="blur1" x="-1" y="-1" width="100" height="100">
</filter> <feGaussianBlur in="SourceGraphic" stdDeviation="1"/>
<filter id="blur5" x="-1" y="-1" width="100" height="100"> </filter>
<feGaussianBlur in="SourceGraphic" stdDeviation="5"/> <filter id="blur5" x="-1" y="-1" width="100" height="100">
</filter> <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
<filter id="blur10" x="-1" y="-1" width="100" height="100"> </filter>
<feGaussianBlur in="SourceGraphic" stdDeviation="10"/> <filter id="blur10" x="-1" y="-1" width="100" height="100">
</filter> <feGaussianBlur in="SourceGraphic" stdDeviation="10"/>
<filter id="splotch"> </filter>
<feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="4"/> <filter id="splotch">
<feColorMatrix values="0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.9 1.2" result="texture"/> <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="4"/>
<feComposite in="SourceGraphic" in2="texture" operator="in"/> <feColorMatrix values="0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.9 1.2" result="texture"/>
</filter> <feComposite in="SourceGraphic" in2="texture" operator="in"/>
<filter id="bluredSplotch"> </filter>
<feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="4"/> <filter id="bluredSplotch">
<feColorMatrix values="0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.9 1.2" result="texture"/> <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="4"/>
<feComposite in="SourceGraphic" in2="texture" operator="in"/> <feColorMatrix values="0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.9 1.2" result="texture"/>
<feGaussianBlur stdDeviation="4"/> <feComposite in="SourceGraphic" in2="texture" operator="in"/>
</filter> <feGaussianBlur stdDeviation="4"/>
<filter id="dropShadow"> </filter>
<feGaussianBlur in="SourceAlpha" stdDeviation="2"/> <filter id="dropShadow">
<feOffset dx="1" dy="2"/> <feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
<feMerge> <feOffset dx="1" dy="2"/>
<feMergeNode/> <feMerge>
<feMergeNode in="SourceGraphic"/> <feMergeNode/>
</feMerge> <feMergeNode in="SourceGraphic"/>
</filter> </feMerge>
<filter id="pencil"> </filter>
<feTurbulence baseFrequency="0.03" numOctaves="6" type="fractalNoise"/> <filter id="pencil">
<feDisplacementMap scale="3" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G"/> <feTurbulence baseFrequency="0.03" numOctaves="6" type="fractalNoise"/>
</filter> <feDisplacementMap scale="3" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G"/>
<filter id="turbulence"> </filter>
<feTurbulence baseFrequency="0.1" numOctaves="3" type="fractalNoise"/> <filter id="turbulence">
<feDisplacementMap scale="10" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G"/> <feTurbulence baseFrequency="0.1" numOctaves="3" type="fractalNoise"/>
</filter> <feDisplacementMap scale="10" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G"/>
<filter id="filter-grayscale"> </filter>
<feColorMatrix values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"/> <filter id="filter-grayscale">
</filter> <feColorMatrix values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"/>
<filter id="filter-sepia"> </filter>
<feColorMatrix values="0.393 0.769 0.189 0 0 0.349 0.686 0.168 0 0 0.272 0.534 0.131 0 0 0 0 0 1 0"/> <filter id="filter-sepia">
</filter> <feColorMatrix values="0.393 0.769 0.189 0 0 0.349 0.686 0.168 0 0 0.272 0.534 0.131 0 0 0 0 0 1 0"/>
<filter id="filter-dingy"> </filter>
<feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0.3 0.3 0 0 0 0 0 1 0"/> <filter id="filter-dingy">
</filter> <feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0.3 0.3 0 0 0 0 0 1 0"/>
<filter id="filter-tint"> </filter>
<feColorMatrix values="1.1 0 0 0 0 0 1.1 0 0 0 0 0 0.9 0 0 0 0 0 1 0"/> <filter id="filter-tint">
</filter> <feColorMatrix values="1.1 0 0 0 0 0 1.1 0 0 0 0 0 0.9 0 0 0 0 0 1 0"/>
</filter>
</g>
<g id="deftemp"> <g id="deftemp">
<mask id="shape" x="0" y="0" width="100%" height="100%" fill="black"></mask> <mask id="shape" x="0" y="0" width="100%" height="100%" fill="black"></mask>
</g> </g>
@ -534,6 +536,7 @@
<div> <div>
Coord: <span id="infoX">0</span>/<span id="infoY">0</span><br> Coord: <span id="infoX">0</span>/<span id="infoY">0</span><br>
Cell: <span id="infoCell">0</span><br> Cell: <span id="infoCell">0</span><br>
Area: <span id="infoArea">0</span><br>
Height: <span id="infoHeight">0</span><br> Height: <span id="infoHeight">0</span><br>
Flux: <span id="infoFlux">0</span> Flux: <span id="infoFlux">0</span>
</div> </div>
@ -541,6 +544,7 @@
Type: <span id="infoFeature">n/a</span><br> Type: <span id="infoFeature">n/a</span><br>
Country: <span id="infoCountry">n/a</span><br> Country: <span id="infoCountry">n/a</span><br>
Culture: <span id="infoCulture">n/a</span><br> Culture: <span id="infoCulture">n/a</span><br>
Population: <span id="infoPopulation">0</span><br>
Burg: <span id="infoBurg">n/a</span> Burg: <span id="infoBurg">n/a</span>
</div> </div>
</div> </div>
@ -1107,5 +1111,5 @@
<input type="file" accept=".txt" id="namesbaseToLoad"> <input type="file" accept=".txt" id="namesbaseToLoad">
</div> </div>
<script src="script.js?version=0.58.00b"></script> <script src="script.js?version=0.58.02b"></script>
</body> </body>

143
script.js
View file

@ -3,7 +3,7 @@
fantasyMap(); fantasyMap();
function fantasyMap() { function fantasyMap() {
// Version control // Version control
var version = "0.58b"; const version = "0.58b";
document.title += " v. " + version; document.title += " v. " + version;
// Declare variables // Declare variables
@ -11,11 +11,11 @@ function fantasyMap() {
defs = svg.select("#deftemp"), defs = svg.select("#deftemp"),
viewbox = svg.append("g").attr("id", "viewbox"), viewbox = svg.append("g").attr("id", "viewbox"),
ocean = viewbox.append("g").attr("id", "ocean"), ocean = viewbox.append("g").attr("id", "ocean"),
lakes = viewbox.append("g").attr("id", "lakes"),
oceanLayers = ocean.append("g").attr("id", "oceanLayers"), oceanLayers = ocean.append("g").attr("id", "oceanLayers"),
oceanPattern = ocean.append("g").attr("id", "oceanPattern"), oceanPattern = ocean.append("g").attr("id", "oceanPattern"),
landmass = viewbox.append("g").attr("id", "landmass"), landmass = viewbox.append("g").attr("id", "landmass"),
terrs = viewbox.append("g").attr("id", "terrs"), terrs = viewbox.append("g").attr("id", "terrs"),
lakes = viewbox.append("g").attr("id", "lakes"),
grid = viewbox.append("g").attr("id", "grid"), grid = viewbox.append("g").attr("id", "grid"),
overlay = viewbox.append("g").attr("id", "overlay"), overlay = viewbox.append("g").attr("id", "overlay"),
routes = viewbox.append("g").attr("id", "routes"), routes = viewbox.append("g").attr("id", "routes"),
@ -414,14 +414,19 @@ function fantasyMap() {
infoX.innerHTML = rn(point[0]); infoX.innerHTML = rn(point[0]);
infoY.innerHTML = rn(point[1]); infoY.innerHTML = rn(point[1]);
infoCell.innerHTML = i; infoCell.innerHTML = i;
infoArea.innerHTML = ifDefined(p.area, "n/a", 2);
infoHeight.innerHTML = ifDefined(p.height, "n/a", 2); infoHeight.innerHTML = ifDefined(p.height, "n/a", 2);
infoFlux.innerHTML = ifDefined(p.flux, "n/a", 2); infoFlux.innerHTML = ifDefined(p.flux, "n/a", 2);
infoFeature.innerHTML = ifDefined(p.f) + "" + ifDefined(p.fn);
let country = p.region === undefined ? "n/a" : p.region === "neutral" ? "neutral" : states[p.region].name + " (" + p.region + ")"; let country = p.region === undefined ? "n/a" : p.region === "neutral" ? "neutral" : states[p.region].name + " (" + p.region + ")";
infoCountry.innerHTML = country; infoCountry.innerHTML = country;
let culture = ifDefined(p.culture) !== "no" ? cultures[p.culture].name + " (" + p.culture + ")" : "n/a"; let culture = ifDefined(p.culture) !== "no" ? cultures[p.culture].name + " (" + p.culture + ")" : "n/a";
infoCulture.innerHTML = culture; infoCulture.innerHTML = culture;
infoPopulation.innerHTML = ifDefined(p.pop, "n/a", 2);
infoBurg.innerHTML = ifDefined(p.manor) !== "no" ? manors[p.manor].name + " (" + p.manor + ")" : "no"; infoBurg.innerHTML = ifDefined(p.manor) !== "no" ? manors[p.manor].name + " (" + p.manor + ")" : "no";
const feature = features[p.fn];
if (feature === undefined) return;
const fType = feature.land ? "Island" : feature.border ? "Ocean" : "Lake";
infoFeature.innerHTML = fType + " (" + p.fn + ")";
} }
// update tooltip // update tooltip
@ -474,8 +479,8 @@ function fantasyMap() {
// return value (v) if defined with specified number of decimals (d) // return value (v) if defined with specified number of decimals (d)
// else return "no" or attribute (r) // else return "no" or attribute (r)
function ifDefined(v, r, d) { function ifDefined(v, r, d) {
if (v == undefined) {return r || "no";} if (v === undefined) return r || "no";
if (d) {return v.toFixed(d);} if (d) return v.toFixed(d);
return v; return v;
} }
@ -1264,7 +1269,6 @@ function fantasyMap() {
calculateVoronoi(newPoints); // recalculate Voronoi diagram using new points calculateVoronoi(newPoints); // recalculate Voronoi diagram using new points
let gridPath = ""; // store grid as huge single path string let gridPath = ""; // store grid as huge single path string
cells.map(function(i, d) { cells.map(function(i, d) {
if (!polygons[d]) debugger;
if (i.height >= 0.2) { if (i.height >= 0.2) {
// calc cell area // calc cell area
i.area = rn(Math.abs(d3.polygonArea(polygons[d])), 2); i.area = rn(Math.abs(d3.polygonArea(polygons[d])), 2);
@ -1408,14 +1412,14 @@ function fantasyMap() {
// Detect and draw the coasline // Detect and draw the coasline
function drawCoastline() { function drawCoastline() {
console.time('drawCoastline'); console.time('drawCoastline');
var oceanCoastline = "", lakeCoastline = ""; const shape = d3.select("#shape");
$("#landmass").empty(); $("#landmass").empty();
let minX = graphWidth, maxX = 0; // extreme points let minX = graphWidth, maxX = 0; // extreme points
let minXedge, maxXedge; // extreme edges let minXedge, maxXedge; // extreme edges
for (let f = 0; f < features.length; f++) { for (let f = 0; f < features.length; f++) {
if (!features[f].land) continue; if (!features[f].land) continue;
const coastal = $.grep(land, function(e) {return ((e.ctype === 1 || e.ctype === 99) && e.fn === f);}); const coastal = $.grep(land, function(e) {return ((e.ctype === 1 || e.ctype === 99) && e.fn === f);});
const oceanEdges = [], lakeEdges = []; let oceanEdges = [], lakeEdges = [];
for (let i = 0; i < coastal.length; i++) { for (let i = 0; i < coastal.length; i++) {
const id = coastal[i].index, cell = diagram.cells[id]; const id = coastal[i].index, cell = diagram.cells[id];
cell.halfedges.forEach(function(e) { cell.halfedges.forEach(function(e) {
@ -1425,15 +1429,15 @@ function fantasyMap() {
if (edge.left && edge.right) { if (edge.left && edge.right) {
const ea = edge.left.index === id ? edge.right.index : edge.left.index; const ea = edge.left.index === id ? edge.right.index : edge.left.index;
if (cells[ea].height < 0.2) { if (cells[ea].height < 0.2) {
if (!features[cells[ea].fn].border) { if (features[cells[ea].fn].border) {
lakeEdges.push({start, end});
} else {
oceanEdges.push({start, end}); oceanEdges.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]}
if (edge[1][0] < minX) {minX = edge[1][0]; minXedge = edge[1]} if (edge[1][0] < minX) {minX = edge[1][0]; minXedge = edge[1]}
if (edge[0][0] > maxX) {maxX = edge[0][0]; maxXedge = edge[0]} if (edge[0][0] > maxX) {maxX = edge[0][0]; maxXedge = edge[0]}
if (edge[1][0] > maxX) {maxX = edge[1][0]; maxXedge = edge[1]} if (edge[1][0] > maxX) {maxX = edge[1][0]; maxXedge = edge[1]}
} else {
lakeEdges.push({start, end});
} }
} }
} else { } else {
@ -1441,17 +1445,21 @@ function fantasyMap() {
} }
}) })
} }
if (coastal.length && lakeEdges.length && oceanEdges.length < 3) {
console.error("Feature " + f + " is an on-lake island. This can cause defects!");
oceanEdges = lakeEdges;
lakeEdges = [];
}
lineGen.curve(d3.curveCatmullRomClosed.alpha(0.1)); lineGen.curve(d3.curveCatmullRomClosed.alpha(0.1));
oceanCoastline += getContinuousLine(oceanEdges, 3, 0); const oceanCoastline = getContinuousLine(oceanEdges, 3, 0);
lineGen.curve(d3.curveBasisClosed); lineGen.curve(d3.curveBasisClosed);
if (lakeEdges.length > 0) {lakeCoastline += getContinuousLine(lakeEdges, 1.5, 0);} const lakeCoastline = getContinuousLine(lakeEdges, 1.5, 0);
shape.append("path").attr("d", oceanCoastline).attr("fill", "white");
if (lakeCoastline) shape.append("path").attr("d", lakeCoastline).attr("fill", "black");
coastline.append("path").attr("d", oceanCoastline); // draw the coastline
if (lakeCoastline) lakes.append("path").attr("d", lakeCoastline); // draw the lakes
} }
const shape = d3.select("#shape"); landmass.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); // draw the landmass
shape.append("path").attr("d", oceanCoastline).attr("fill", "white"); // add clippath
shape.append("path").attr("d", lakeCoastline).attr("fill", "black"); // add clippath
landmass.append("path").attr("d", oceanCoastline + lakeCoastline); // draw the landmass
coastline.append("path").attr("d", oceanCoastline); // draw the coastline
lakes.append("path").attr("d", lakeCoastline); // draw the lakes
drawDefaultRuler(minXedge, maxXedge); drawDefaultRuler(minXedge, maxXedge);
console.timeEnd('drawCoastline'); console.timeEnd('drawCoastline');
} }
@ -1658,6 +1666,7 @@ function fantasyMap() {
function getContinuousLine(edges, indention, relax) { function getContinuousLine(edges, indention, relax) {
let line = ""; let line = "";
if (edges.length < 3) return "";
while (edges.length > 2) { while (edges.length > 2) {
let edgesOrdered = []; // to store points in a correct order let edgesOrdered = []; // to store points in a correct order
let start = edges[0].start; let start = edges[0].start;
@ -1706,14 +1715,17 @@ function fantasyMap() {
// temporary elevate lakes to min neighbors heights to correctly flux the water // temporary elevate lakes to min neighbors heights to correctly flux the water
function elevateLakes() { function elevateLakes() {
for (let i=0; i < cells.length; i++) { console.time('elevateLakes');
if (cells[i].height >= 0.2) continue; const lakes = $.grep(cells, function(e) {return e.height < 0.2 && !features[e.fn].border;});
if (features[cells[i].fn].border) continue; lakes.sort(function(a, b) {return b.height - a.height;});
const heights = cells[i].neighbors.map(function(n) {if (cells[n].height >= 0.2) return cells[n].height}); for (let i=0; i < lakes.length; i++) {
if (heights.length) cells[i].height = d3.mean(heights) - 0.02; const heights = [];
if (cells[i].height < 0.2) cells[i].height = 0.2; lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 0.2) heights.push(cells[n].height)});
cells[i].lake = true; if (heights.length) lakes[i].height = d3.min(heights) - 0.01;
if (cells[i].height < 0.2) lakes[i].height = 0.2;
lakes[i].lake = true;
} }
console.timeEnd('elevateLakes');
} }
// Depression filling algorithm (for a correct water flux modeling; phase1) // Depression filling algorithm (for a correct water flux modeling; phase1)
@ -1835,7 +1847,7 @@ function fantasyMap() {
} }
} }
} }
cells[min].flux += land[i].flux; if (cells[min].flux) cells[min].flux += land[i].flux;
if (land[i].river !== undefined) { if (land[i].river !== undefined) {
const px = cells[min].data[0]; const px = cells[min].data[0];
const py = cells[min].data[1]; const py = cells[min].data[1];
@ -2025,12 +2037,12 @@ function fantasyMap() {
} }
if (land[i].lake === 2) { if (land[i].lake === 2) {
if (land[i].river !== undefined) { if (land[i].river !== undefined) {
addLakeAtCell(i); addLakeAtCell(land[i].index);
} else { } else {
//land[i].lake = undefined; delete land[i].lake;
land[i].neighbors.forEach(function(n) { land[i].neighbors.forEach(function(n) {
if (cells[n].river !== undefined) { if (cells[n].river !== undefined) {
addLakeAtCell(i); addLakeAtCell(n);
return; return;
} }
}); });
@ -2039,18 +2051,18 @@ function fantasyMap() {
} }
function addLakeAtCell(i) { function addLakeAtCell(i) {
land[i].height = 0.19; cells[i].lake = 2;
land[i].ctype = -1; cells[i].height = 0.19;
cells[i].ctype = -1;
let fn = features.length; let fn = features.length;
land[i].neighbors.forEach(function(e) { cells[i].neighbors.forEach(function(e) {
if (cells[e].height >= 0.2) cells[e].ctype = 1; if (cells[e].height >= 0.2) cells[e].ctype = 1;
// change fn to neighboring lake // change fn to neighboring lake
if (cells[e].lake) fn = cells[e].fn; if (cells[e].lake === 2 && cells[e].river !== undefined) fn = cells[e].fn;
else if (cells[e].lake === 1) fn = cells[e].fn;
}); });
land[i].fn = fn; cells[i].fn = fn;
if (fn === features.length) { if (fn === features.length) features.push({i: fn, land: false, border: false});
features.push({i: features.length, land: false, border: false});
}
} }
land = $.grep(cells, function(e) {return e.height >= 0.2;}); land = $.grep(cells, function(e) {return e.height >= 0.2;});
@ -3303,7 +3315,7 @@ function fantasyMap() {
// calculate population for manors, cells and states // calculate population for manors, cells and states
function calculatePopulation() { function calculatePopulation() {
// neutral population factors < 1 as neutral lands are usually pretty wild // neutral population factors < 1 as neutral lands are usually pretty wild
var ruralFactor = 0.5, urbanFactor = 0.9; const ruralFactor = 0.5, urbanFactor = 0.9;
// calculate population for each burg (based on trade/people attractors) // calculate population for each burg (based on trade/people attractors)
manors.map(function(m) { manors.map(function(m) {
@ -3986,7 +3998,6 @@ function fantasyMap() {
let dist = 100000, manor = null; let dist = 100000, manor = null;
if (manors.length) { if (manors.length) {
const c = manorTree.find(x, y); const c = manorTree.find(x, y);
if (!c) debugger;
dist = Math.hypot(c[0] - x, c[1] - y); dist = Math.hypot(c[0] - x, c[1] - y);
manor = getManorId(c); manor = getManorId(c);
} }
@ -4233,7 +4244,7 @@ function fantasyMap() {
console.time("recalculateCultures"); console.time("recalculateCultures");
// For each capital find closest culture and assign it to capital // For each capital find closest culture and assign it to capital
states.forEach(function(s) { states.forEach(function(s) {
if (s.capital === "neutral") return; if (s.capital === "neutral" || s.capital === "select") return;
const capital = manors[s.capital]; const capital = manors[s.capital];
const c = cultureTree.find(capital.x, capital.y); const c = cultureTree.find(capital.x, capital.y);
capital.culture = getCultureId(c); capital.culture = getCultureId(c);
@ -4389,7 +4400,7 @@ function fantasyMap() {
delete c.coastY; delete c.coastY;
if (c.ctype === undefined) {delete c.ctype;} if (c.ctype === undefined) {delete c.ctype;}
c.height = rn(c.height, 2); c.height = rn(c.height, 2);
c.flux = rn(c.flux, 2); if (c.height >= 0.2) c.flux = rn(c.flux, 2);
}); });
// restore layers if they was turned on // restore layers if they was turned on
if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) toggleHeight(); if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) toggleHeight();
@ -5715,6 +5726,20 @@ function fantasyMap() {
if(data[8]) nameBase = JSON.parse(data[8]); if(data[8]) nameBase = JSON.parse(data[8]);
if(data[8]) nameBases = JSON.parse(data[9]); if(data[8]) nameBases = JSON.parse(data[9]);
// 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;
i.area = rn(Math.abs(d3.polygonArea(polygons[p])), 2);
if (i.pop === undefined) {
let population = 0;
const elevationFactor = Math.pow(1 - i.height, 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) {
optionsTrigger.click(); optionsTrigger.click();
@ -5845,6 +5870,9 @@ function fantasyMap() {
case 83: // "S" to log states data case 83: // "S" to log states data
console.table(states); console.table(states);
break; break;
case 70: // "F" to log features data
console.table(features);
break;
case 37: // Left to scroll map left case 37: // Left to scroll map left
zoom.translateBy(svg, 10, 0); zoom.translateBy(svg, 10, 0);
break; break;
@ -5960,8 +5988,7 @@ function fantasyMap() {
$("#countriesManuallyButtons").show(); $("#countriesManuallyButtons").show();
// highlight capital cells as it's not allowed to change capital's state that way // highlight capital cells as it's not allowed to change capital's state that way
states.map(function(s) { states.map(function(s) {
if (s.color === "neutral") {return;} if (s.capital === "neutral" || s.capital === "select") return;
if (s.capital === "select") {return;}
const capital = s.capital; const capital = s.capital;
const index = manors[capital].cell; const index = manors[capital].cell;
temp.append("path") temp.append("path")
@ -6549,30 +6576,28 @@ function fantasyMap() {
function editHeightmap(type) { function editHeightmap(type) {
closeDialogs(); closeDialogs();
var heights = [], regionData = [], cultureData = []; const heights = [], regionData = [], cultureData = [];
for (var i = 0; i < points.length; i++) { for (let i = 0; i < points.length; i++) {
var cell = diagram.find(points[i][0], points[i][1]).index; const cell = diagram.find(points[i][0], points[i][1]).index;
heights.push(cells[cell].height); heights.push(cells[cell].height);
var 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);
var culture = cells[cell].culture; let culture = cells[cell].culture;
if (culture === undefined) {culture = -1;} if (culture === undefined) culture = -1;
cultureData.push(culture); cultureData.push(culture);
} }
if (type === "clean") {undraw();} if (type === "clean") undraw();
calculateVoronoi(points); calculateVoronoi(points);
detectNeighbors("grid"); detectNeighbors("grid");
drawScaleBar(); drawScaleBar();
for (var i = 0; i < points.length; i++) { for (let i = 0; i < points.length; i++) {cells[i].height = heights[i];}
cells[i].height = heights[i];
}
if (type === "keep") { if (type === "keep") {
svg.selectAll("#shape, #lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions") svg.selectAll("#shape, #lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions")
.selectAll("path, circle, line").remove(); .selectAll("path, circle, line").remove();
for (var i = 0; i < points.length; i++) { for (let i = 0; i < points.length; i++) {
if (regionData[i] !== -1) {cells[i].region = regionData[i];} if (regionData[i] !== -1) cells[i].region = regionData[i];
if (cultureData[i] !== -1) {cells[i].culture = cultureData[i];} if (cultureData[i] !== -1) cells[i].culture = cultureData[i];
} }
} }
mockHeightmap(); mockHeightmap();
@ -8468,7 +8493,7 @@ function fantasyMap() {
neutralBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .3).attr("stroke-dasharray", "1 1.5").attr("stroke-linecap", "butt"); neutralBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .3).attr("stroke-dasharray", "1 1.5").attr("stroke-linecap", "butt");
cults.attr("opacity", .6); cults.attr("opacity", .6);
rivers.attr("opacity", 1).attr("fill", "#5d97bb"); rivers.attr("opacity", 1).attr("fill", "#5d97bb");
lakes.attr("opacity", .5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", .25); lakes.attr("opacity", .5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", .7);
icons.selectAll("g").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b"); icons.selectAll("g").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b");
roads.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .35).attr("stroke-dasharray", "1.5").attr("stroke-linecap", "butt"); roads.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .35).attr("stroke-dasharray", "1.5").attr("stroke-linecap", "butt");
trails.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .15).attr("stroke-dasharray", ".8 1.6").attr("stroke-linecap", "butt"); trails.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .15).attr("stroke-dasharray", ".8 1.6").attr("stroke-linecap", "butt");