Skip to content

Commit 5ffd30d

Browse files
author
Azgaar
committed
v 1.21
1 parent a3fa544 commit 5ffd30d

19 files changed

+686
-412
lines changed

index.css

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ button.active {
593593

594594
#viewMode > button {
595595
padding: .35em;
596-
margin: .2em .3em;
596+
margin: .2em .3em .6em .3em;
597597
float: left;
598598
width: 30.7%;
599599
}
@@ -1287,6 +1287,10 @@ div.states span.inactive:hover {
12871287
color: #abaaaa;
12881288
}
12891289

1290+
div.states>input.riverType {
1291+
width: 5em;
1292+
}
1293+
12901294
#diplomacyBodySection > div {
12911295
cursor: pointer;
12921296
}
@@ -1976,6 +1980,13 @@ svg.button {
19761980
border: 1px solid #916e7f;
19771981
}
19781982

1983+
.announcement {
1984+
background-color: #a18888;
1985+
color: white;
1986+
padding: .4em .5em;
1987+
border: dashed 1px #5d4651;
1988+
}
1989+
19791990
#debug {
19801991
font-size: 1px;
19811992
opacity: .8;

index.html

Lines changed: 108 additions & 80 deletions
Large diffs are not rendered by default.

libs/jquery-ui.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

main.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
// See also https://github.com/Azgaar/Fantasy-Map-Generator/issues/153
88

99
"use strict";
10-
const version = "1.2"; // generator version
10+
const version = "1.21"; // generator version
1111
document.title += " v" + version;
1212

1313
// if map version is not stored, clear localStorage and show a message
14-
if (rn(localStorage.getItem("version"),1) !== rn(version,1)) {
14+
if (rn(localStorage.getItem("version"), 2) !== rn(version, 2)) {
1515
localStorage.clear();
1616
setTimeout(showWelcomeMessage, 8000);
1717
}
@@ -325,10 +325,18 @@ function showWelcomeMessage() {
325325
This version is compatible with ${changelog}, loaded <i>.map</i> files will be auto-updated.
326326
327327
<ul>${post}
328-
<li>3d scene</li>
329-
<li>Globe view</li>
328+
<li>3d scene and Globe view</li>
329+
<li>Ability to save map as JPEG image</li>
330+
<li>Diplomacy Editor enhancements</li>
331+
<li>Rivers Overview screen [v 1.21] <b>*</b></li>
330332
</ul>
331333
334+
<p style="color:#990000; font-style: italic"><b>*</b> It's recommended to regenerate rivers to get clean data for Rivers Overview.<p>
335+
336+
<p class="announcement">We are happy to invite you to participate in our first map making contest!
337+
Valuable prizes for winners and our respect for all participants.
338+
See ${link("https://www.reddit.com/r/FantasyMapGenerator/comments/dn2sqv/azgaars_fantasy_map_generator_mapmaking_contest/", "Reddit post")} for the details.</p>
339+
332340
<p>Join our ${reddit} and ${discord} to ask questions, share maps, discuss the Generator, report bugs and propose new features.</p>
333341
<p>Thanks for all supporters on ${patreon}!</i></p>`;
334342

@@ -513,6 +521,8 @@ function generate() {
513521
drawStates();
514522
drawBorders();
515523
BurgsAndStates.drawStateLabels();
524+
525+
Rivers.specify();
516526
addMarkers();
517527
addZones();
518528
Names.getMapName();
@@ -1222,9 +1232,9 @@ function addMarkers(number = 1) {
12221232
.attr("data-size", 1).attr("width", 30).attr("height", 30);
12231233

12241234
const burg = pack.burgs[cells.burg[cell]];
1225-
const river = Names.getCulture(cells.culture[cell]); // river name
1226-
const name = Math.random() < .2 ? river : burg.name;
1227-
notes.push({id, name:`${name} Bridge`, legend:`A stone bridge over the ${river} River near ${burg.name}`});
1235+
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
1236+
const name = Math.random() < .2 ? river.name : burg.name;
1237+
notes.push({id, name:`${name} Bridge`, legend:`A stone bridge over the ${river.name} ${river.type} near ${burg.name}`});
12281238
count--;
12291239
}
12301240
}()

modules/river-generator.js

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,16 @@
7373
riversData.push({river: riverNext, cell: i, x, y});
7474
riverNext++;
7575
}
76-
76+
7777
if (cells.r[min]) { // downhill cell already has river assigned
7878
if (cells.fl[min] < cells.fl[i]) {
79-
cells.conf[min] = cells.fl[min]; // confluence
79+
cells.conf[min] = cells.fl[min]; // mark confluence
80+
if (h[min] >= 20) riversData.find(r => r.river === cells.r[min]).parent = cells.r[i]; // min river is a tributary of current river
8081
cells.r[min] = cells.r[i]; // re-assign river if downhill part has less flux
81-
} else cells.conf[min] += cells.fl[i]; // confluence
82+
} else {
83+
cells.conf[min] += cells.fl[i]; // mark confluence
84+
if (h[min] >= 20) riversData.find(r => r.river === cells.r[i]).parent = cells.r[min]; // current river is a tributary of min river
85+
}
8286
} else cells.r[min] = cells.r[i]; // assign the river to the downhill cell
8387

8488
const nx = p[min][0], ny = p[min][1];
@@ -99,25 +103,29 @@
99103

100104
});
101105
}()
102-
103-
void function drawRivers() {
104-
const riverPaths = []; // to store data for all rivers
106+
107+
void function defineRivers() {
108+
pack.rivers = []; // rivers data
109+
const riverPaths = []; // temporary data for all rivers
105110

106111
for (let r = 1; r <= riverNext; r++) {
107112
const riverSegments = riversData.filter(d => d.river === r);
108-
113+
109114
if (riverSegments.length > 2) {
110115
const riverEnhanced = addMeandring(riverSegments);
111-
const width = rn(0.8 + Math.random() * 0.4, 1); // river width modifier
112-
const increment = rn(0.8 + Math.random() * 0.6, 1); // river bed widening modifier
113-
const path = getPath(riverEnhanced, width, increment);
116+
const width = rn(.8 + Math.random() * .4, 1); // river width modifier
117+
const increment = rn(.8 + Math.random() * .6, 1); // river bed widening modifier
118+
const [path, length] = getPath(riverEnhanced, width, increment);
114119
riverPaths.push([r, path, width, increment]);
120+
const parent = riverSegments[0].parent || 0;
121+
pack.rivers.push({i:r, parent, length, source:riverSegments[0].cell, mouth:last(riverSegments).cell});
115122
} else {
116123
// remove too short rivers
117124
riverSegments.filter(s => cells.r[s.cell] === r).forEach(s => cells.r[s.cell] = 0);
118125
}
119126
}
120127

128+
// drawRivers
121129
rivers.selectAll("path").remove();
122130
rivers.selectAll("path").data(riverPaths).enter()
123131
.append("path").attr("d", d => d[1]).attr("id", d => "river"+d[0])
@@ -129,12 +137,10 @@
129137

130138
// depression filling algorithm (for a correct water flux modeling)
131139
const resolveDepressions = function(h) {
132-
console.time('resolveDepressions');
133140
const cells = pack.cells;
134141
const land = cells.i.filter(i => h[i] >= 20 && h[i] < 100 && !cells.b[i]); // exclude near-border cells
135142
land.sort((a,b) => h[b] - h[a]); // highest cells go first
136143
let depressed = false;
137-
const depressions = [];
138144

139145
for (let l = 0, depression = Infinity; depression && l < 100; l++) {
140146
depression = 0;
@@ -147,12 +153,8 @@
147153
depressed = true;
148154
}
149155
}
150-
depressions.push(depression);
151156
}
152157

153-
console.log(depressions);
154-
155-
console.timeEnd('resolveDepressions');
156158
return depressed;
157159
}
158160

@@ -242,9 +244,56 @@
242244
const right = lineGen(riverPointsRight);
243245
let left = lineGen(riverPointsLeft);
244246
left = left.substring(left.indexOf("C"));
245-
return round(right + left, 2);
247+
return [round(right + left, 2), rn(riverLength, 2)];
248+
}
249+
250+
const specify = function() {
251+
if (!pack.rivers.length) return;
252+
const smallLength = pack.rivers.map(r => r.length||0).sort((a,b) => a-b)[Math.ceil(pack.rivers.length * .15)];
253+
const smallType = {"Creek":9, "River":3, "Brook":3, "Stream":1}; // weighted small river types
254+
255+
for (const r of pack.rivers) {
256+
r.basin = getBasin(r.i, r.parent);
257+
r.name = getName(r.mouth);
258+
const small = r.length < smallLength;
259+
r.type = r.parent && !(r.i%6) ? small ? "Branch" : "Fork" : small ? rw(smallType) : "River";
260+
}
261+
262+
return;
263+
const basins = [...(new Set(pack.rivers.map(r=>r.basin)))];
264+
const colors = getColors(basins.length);
265+
basins.forEach((b,i) => {
266+
pack.rivers.filter(r => r.basin === b).forEach(r => {
267+
rivers.select("#river"+r.i).attr("fill", colors[i]);
268+
});
269+
});
270+
271+
}
272+
273+
const getName = function(cell) {
274+
return Names.getCulture(pack.cells.culture[cell]);
275+
}
276+
277+
// remove river and all its tributaries
278+
const remove = function(id) {
279+
const riversToRemove = pack.rivers.filter(r => r.i === id || getBasin(r.i, r.parent, id) === id).map(r => r.i);
280+
riversToRemove.forEach(r => rivers.select("#river"+r).remove());
281+
pack.cells.r.forEach((r, i) => {
282+
if (r && riversToRemove.includes(r)) pack.cells.r[i] = 0;
283+
});
284+
pack.rivers = pack.rivers.filter(r => !riversToRemove.includes(r.i));
285+
}
286+
287+
const getBasin = function(r, p, e) {
288+
while (p) {
289+
const parent = pack.rivers.find(r => r.i === p);
290+
if (parent) r = parent.i;
291+
p = parent ? parent.parent : 0;
292+
if (r === e) return r;
293+
}
294+
return r;
246295
}
247296

248-
return {generate, resolveDepressions, addMeandring, getPath};
297+
return {generate, resolveDepressions, addMeandring, getPath, specify, getName, getBasin, remove};
249298

250299
})));

modules/save-and-load.js

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ function getMapData() {
250250
const burgs = JSON.stringify(pack.burgs);
251251
const religions = JSON.stringify(pack.religions);
252252
const provinces = JSON.stringify(pack.provinces);
253+
const rivers = JSON.stringify(pack.rivers);
253254

254255
// store name array only if it is not the same as default
255256
const defaultNB = Names.getNameBases();
@@ -268,7 +269,7 @@ function getMapData() {
268269
pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl,
269270
pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state,
270271
pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces,
271-
namesData].join("\r\n");
272+
namesData, rivers].join("\r\n");
272273
const blob = new Blob([data], {type: "text/plain"});
273274

274275
console.timeEnd("createMapDataBlob");
@@ -293,23 +294,6 @@ async function saveMap() {
293294
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
294295
}
295296

296-
// download map data as GeoJSON
297-
function saveGeoJSON() {
298-
alertMessage.innerHTML = `You can export map data in GeoJSON format used in GIS tools such as QGIS.
299-
Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/GIS-data-export", "wiki-page")} for guidance`;
300-
301-
$("#alert").dialog({title: "GIS data export", resizable: false, width: "32em", position: {my: "center", at: "center", of: "svg"},
302-
buttons: {
303-
Cells: saveGeoJSON_Cells,
304-
Routes: saveGeoJSON_Roads,
305-
Rivers: saveGeoJSON_Rivers,
306-
Markers: saveGeoJSON_Markers,
307-
Close: function() {$(this).dialog("close");}
308-
}
309-
});
310-
}
311-
312-
313297
function saveGeoJSON_Cells() {
314298
let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n";
315299
const cells = pack.cells, v = pack.vertices;
@@ -686,6 +670,7 @@ function parseLoadedData(data) {
686670
pack.burgs = JSON.parse(data[15]);
687671
pack.religions = data[29] ? JSON.parse(data[29]) : [{i: 0, name: "No religion"}];
688672
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
673+
pack.rivers = data[32] ? JSON.stringify(data[32]) : [];
689674

690675
const cells = pack.cells;
691676
cells.biome = Uint8Array.from(data[16].split(","));
@@ -899,21 +884,37 @@ function parseLoadedData(data) {
899884
});
900885
}
901886

887+
// v 1.11 had an issue with fogging being displayed on load
888+
unfog();
889+
890+
// v 1.2 added new terrain attributes
891+
if (!terrain.attr("set")) terrain.attr("set", "simple");
892+
if (!terrain.attr("size")) terrain.attr("size", 1);
893+
if (!terrain.attr("density")) terrain.attr("density", .4);
894+
}
895+
896+
if (version < 1.21) {
902897
// v 1.11 replaced "display" attribute by "display" style
903898
viewbox.selectAll("g").each(function() {
904899
if (this.hasAttribute("display")) {
905-
this.removeAttribute("display");
900+
this.removeAttribute("display");
906901
this.style.display = "none";
907902
}
908903
});
909904

910-
// v 1.11 had an issue with fogging being displayed on load
911-
unfog();
905+
// v 1.21 added rivers data to pack
906+
907+
pack.rivers = []; // rivers data
908+
rivers.selectAll("path").each(function() {
909+
const i = +this.id.slice(5);
910+
const length = this.getTotalLength() / 2;
911+
const s = this.getPointAtLength(length), e = this.getPointAtLength(0);
912+
const source = findCell(s.x, s.y), mouth = findCell(e.x, e.y);
913+
const name = Rivers.getName(mouth);
914+
const type = length < 25 ? rw({"Creek":9, "River":3, "Brook":3, "Stream":1}) : "River";
915+
pack.rivers.push({i, parent:0, length, source, mouth, basin:i, name, type});
916+
});
912917

913-
// v 1.2 added new terrain attributes
914-
if (!terrain.attr("set")) terrain.attr("set", "simple");
915-
if (!terrain.attr("size")) terrain.attr("size", 1);
916-
if (!terrain.attr("density")) terrain.attr("density", .4);
917918
}
918919

919920
}()

modules/ui/burg-editor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function editBurg(id) {
3030
document.getElementById("burgAddGroup").addEventListener("click", toggleNewGroupInput);
3131
document.getElementById("burgRemoveGroup").addEventListener("click", removeBurgsGroup);
3232

33-
document.getElementById("burgName").addEventListener("input", changeName);
33+
document.getElementById("burgName").addEventListener("input", changeName);
3434
document.getElementById("burgNameReCulture").addEventListener("click", generateNameCulture);
3535
document.getElementById("burgNameReRandom").addEventListener("click", generateNameRandom);
3636
document.getElementById("burgPopulation").addEventListener("change", changePopulation);

0 commit comments

Comments
 (0)