From b759d23df092210d03665d192a2e2a08bb7eeb54 Mon Sep 17 00:00:00 2001 From: Evolvedexperiment Date: Sun, 21 Jun 2020 17:38:23 +0000 Subject: [PATCH 01/38] Fix for last burg sometimes not appearing in elevation-profile --- modules/ui/elevation-profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/elevation-profile.js b/modules/ui/elevation-profile.js index c47c833c..995f0270 100644 --- a/modules/ui/elevation-profile.js +++ b/modules/ui/elevation-profile.js @@ -83,7 +83,7 @@ function showElevationProfile(data, routeLen, isRiver) { chartData.ma = Math.max(chartData.ma, chartData.height[i]); } - if (lastBurgIndex != 0 && lastBurgCell == chartData.cell[data.length-1] && lastBurgIndex < data.length) { + if (lastBurgIndex != 0 && lastBurgCell == chartData.cell[data.length-1] && lastBurgIndex < data.length-1) { chartData.burg[data.length-1] = chartData.burg[lastBurgIndex]; chartData.burg[lastBurgIndex] = 0; } From 783ea4a35f3ce98d0f2dacb8cfd0fac9804c2113 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 21 Jun 2020 20:54:48 +0300 Subject: [PATCH 02/38] v1.4.30 --- modules/ui/options.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/ui/options.js b/modules/ui/options.js index 4d789173..f5f2d4b9 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -109,6 +109,8 @@ optionsContent.addEventListener("change", function(event) { if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value); else if (id === "optionsSeed") generateMapWithSeed(); else if (id === "uiSizeInput") changeUIsize(value); + else if (id === "yearInput") changeYear(); + else if (id === "eraInput") changeEra(); }); optionsContent.addEventListener("click", function(event) { @@ -408,6 +410,18 @@ function regenerateEra() { options.eraShort = options.era.split(" ").map(w => w[0].toUpperCase()).join(""); } +function changeYear() { + if (!yearInputthis.value) return; + if (isNaN(+yearInput.value)) {tip("Current year should be a number", false, "error"); return;} + options.year = +yearInput.value; +} + +function changeEra() { + if (!eraInput.value) return; + lock("era"); + options.era = eraInput.value; +} + // remove all saved data from LocalStorage and reload the page function restoreDefaultOptions() { localStorage.clear(); From 46b94c01ef3ab23143c02bd00bbe2f4a520584c8 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 21 Jun 2020 23:36:36 +0300 Subject: [PATCH 03/38] v1.4.31 --- modules/ui/states-editor.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index 5740b1ee..f4c123a7 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -454,15 +454,6 @@ function editStates() { }); armies.select("g#army"+state).remove(); - const military = pack.states[elSelected.dataset.state].military; - const regIndex = military.indexOf(regiment()); - if (regIndex === -1) return; - military.splice(regIndex, 1); - - const index = notes.findIndex(n => n.id === elSelected.id); - if (index != -1) notes.splice(index, 1); - elSelected.remove(); - const capital = pack.states[state].capital; pack.burgs[capital].capital = 0; pack.burgs[capital].state = 0; From 7fa056fe983b3fc1112825927df6e1bc8f9acdeb Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 22 Jun 2020 01:19:53 +0300 Subject: [PATCH 04/38] v1.4.32 --- modules/burgs-and-states.js | 12 +++++++----- modules/ui/options.js | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index b3083ac6..1fb2d9b5 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -599,14 +599,15 @@ // generate historical conflicts of each state const generateCampaigns = function() { - const wars = {"War":4, "Conflict":2, "Campaign":4, "Invasion":2, "Rebellion":2, "Conquest":2, "Intervention":1, "Expedition":1, "Crusade":1}; + const wars = {"War":6, "Conflict":2, "Campaign":4, "Invasion":2, "Rebellion":2, "Conquest":2, "Intervention":1, "Expedition":1, "Crusade":1}; pack.states.forEach(s => { if (!s.i || s.removed) return; const n = s.neighbors.length ? s.neighbors : [0]; s.campaigns = n.map(i => { const name = i && P(.8) ? pack.states[i].name : Names.getCultureShort(s.culture); - const start = gauss(options.year-100, 150, 1, options.year-6), end = start + gauss(4, 5, 1, options.year - start - 1); + const start = gauss(options.year-100, 150, 1, options.year-6); + const end = start + gauss(4, 5, 1, options.year - start - 1); return {name:getAdjective(name) + " " + rw(wars), start, end}; }).sort((a, b) => a.start - b.start); }); @@ -689,9 +690,10 @@ // start a war const war = [`${an}-${trimVowels(dn)}ian War`,`${an} declared a war on its rival ${dn}`]; - const start = options.year - gauss(2, 2, 0, 5); - states[attacker].campaigns.push({name: `${trimVowels(dn)}ian War`, start, end:options.year}); - states[defender].campaigns.push({name: `${trimVowels(an)}ian War`, start, end:options.year}); + const end = options.year; + const start = end - gauss(2, 2, 0, 5); + states[attacker].campaigns.push({name: `${trimVowels(dn)}ian War`, start, end}); + states[defender].campaigns.push({name: `${trimVowels(an)}ian War`, start, end}); // attacker vassals join the war ad.forEach((r, d) => {if (r === "Suzerain") { diff --git a/modules/ui/options.js b/modules/ui/options.js index f5f2d4b9..581800c0 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -399,7 +399,7 @@ function randomizeCultureSet() { function generateEra() { if (!stored("year")) yearInput.value = rand(100, 2000); // current year if (!stored("era")) eraInput.value = Names.getBaseShort(P(.7) ? 1 : rand(nameBases.length)) + " Era"; - options.year = yearInput.value; + options.year = +yearInput.value; options.era = eraInput.value; options.eraShort = options.era.split(" ").map(w => w[0].toUpperCase()).join(""); // short name for era } From 361b66a186c040230172658159afcefce1a1df09 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 22 Jun 2020 02:00:53 +0300 Subject: [PATCH 05/38] v1.4.33 --- index.html | 3 ++- main.js | 2 +- modules/ui/general.js | 3 ++- modules/ui/notes-editor.js | 10 ++++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index eaf4bf58..d72ca539 100644 --- a/index.html +++ b/index.html @@ -3212,11 +3212,12 @@
- Legend:
+ Note:
+ diff --git a/main.js b/main.js index 5265820a..cd76e80b 100644 --- a/main.js +++ b/main.js @@ -117,7 +117,7 @@ let scale = 1, viewX = 0, viewY = 0; const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", zoomed); // default options -let options = {}; // options object +let options = {pinNotes:false}; // options object let mapCoordinates = {}; // map coordinates on globe options.winds = [225, 45, 225, 315, 135, 315]; // default wind directions diff --git a/modules/ui/general.js b/modules/ui/general.js index 3546f018..7689b1b5 100644 --- a/modules/ui/general.js +++ b/modules/ui/general.js @@ -61,6 +61,7 @@ function moved() { // show note box on hover (if any) function showNotes(e, i) { + if (notesEditor.offsetParent) return; let id = e.target.id || e.target.parentNode.id || e.target.parentNode.parentNode.id; if (e.target.parentNode.parentNode.id === "burgLabels") id = "burg" + e.target.dataset.id; else if (e.target.parentNode.parentNode.id === "burgIcons") id = "burg" + e.target.dataset.id; @@ -70,7 +71,7 @@ function showNotes(e, i) { document.getElementById("notes").style.display = "block"; document.getElementById("notesHeader").innerHTML = note.name; document.getElementById("notesBody").innerHTML = note.legend; - } else { + } else if (!options.pinNotes) { document.getElementById("notes").style.display = "none"; document.getElementById("notesHeader").innerHTML = ""; document.getElementById("notesBody").innerHTML = ""; diff --git a/modules/ui/notes-editor.js b/modules/ui/notes-editor.js index cc49d536..939c97ea 100644 --- a/modules/ui/notes-editor.js +++ b/modules/ui/notes-editor.js @@ -18,6 +18,7 @@ function editNotes(id, name) { select.value = id; notesName.value = note.name; notesText.value = note.legend; + showNote(note); } else { const value = "There are no added notes. Click on element (e.g. label) and add a free text note"; document.getElementById("notesText").value = value; @@ -37,12 +38,19 @@ function editNotes(id, name) { document.getElementById("notesSelect").addEventListener("change", changeObject); document.getElementById("notesName").addEventListener("input", changeName); document.getElementById("notesText").addEventListener("input", changeText); + document.getElementById("notesPin").addEventListener("click", () => options.pinNotes = !options.pinNotes); document.getElementById("notesFocus").addEventListener("click", validateHighlightElement); document.getElementById("notesDownload").addEventListener("click", downloadLegends); document.getElementById("notesUpload").addEventListener("click", () => legendsToLoad.click()); document.getElementById("legendsToLoad").addEventListener("change", function() {uploadFile(this, uploadLegends)}); document.getElementById("notesRemove").addEventListener("click", triggerNotesRemove); + function showNote(note) { + document.getElementById("notes").style.display = "block"; + document.getElementById("notesHeader").innerHTML = note.name; + document.getElementById("notesBody").innerHTML = note.legend; + } + function changeObject() { const note = notes.find(note => note.id === this.value); if (!note) return; @@ -55,6 +63,7 @@ function editNotes(id, name) { const note = notes.find(note => note.id === id); if (!note) return; note.name = this.value; + showNote(note); } function changeText() { @@ -62,6 +71,7 @@ function editNotes(id, name) { const note = notes.find(note => note.id === id); if (!note) return; note.legend = this.value; + showNote(note); } function validateHighlightElement() { From a3f75c7f2729d870a7e6ceaea46f141143fb4d79 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 22 Jun 2020 02:07:10 +0300 Subject: [PATCH 06/38] v1.4.34 --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index d72ca539..e66b78d3 100644 --- a/index.html +++ b/index.html @@ -2538,7 +2538,7 @@ Attackers
-
+
@@ -2551,7 +2551,7 @@ Defenders
-
+
From 7224addbc605879b2085c89cf4f0f2595c756448 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 22 Jun 2020 02:22:55 +0300 Subject: [PATCH 07/38] v1.4.35 --- modules/ui/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index 581800c0..72e39b21 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -411,7 +411,7 @@ function regenerateEra() { } function changeYear() { - if (!yearInputthis.value) return; + if (!yearInput.value) return; if (isNaN(+yearInput.value)) {tip("Current year should be a number", false, "error"); return;} options.year = +yearInput.value; } From 300a05b75db3516f918d715f9bb56c200302a81a Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 23 Jun 2020 02:29:39 +0300 Subject: [PATCH 08/38] v1.4.36 --- index.css | 41 +++++++- index.html | 9 +- libs/pell.js | 163 ++++++++++++++++++++++++++++++++ libs/publicstorage.js | 188 ------------------------------------- modules/save-and-load.js | 7 +- modules/ui/notes-editor.js | 31 +++--- modules/utils.js | 4 +- 7 files changed, 231 insertions(+), 212 deletions(-) create mode 100644 libs/pell.js delete mode 100644 libs/publicstorage.js diff --git a/index.css b/index.css index 57d0df7f..3b577177 100644 --- a/index.css +++ b/index.css @@ -2089,9 +2089,10 @@ svg.button { padding: 1.2em; border: solid 1px #000; font-size: 1.2em; + z-index: 1000; } -#promptTest { +#promptText { padding: 0 0 .6em 0; font-weight: bold; font-family: sans-serif; @@ -2125,6 +2126,44 @@ svg.button { stroke-width: 0; } +.pell { + border: 1px solid hsla(0,0%,4%,.1) +} + +.pell,.pell-content { + box-sizing: border-box +} + +.pell-content { + height: 14em; + outline: 0; + overflow-y: auto; + padding: .6em; + font-family: Copperplate, monospace; + background-color: #fff; + border: 1px solid #dedede; +} + +.pell-actionbar { + background-color: #fff; + border: 1px solid #dedede; + border-bottom: 0; +} + +.pell-button { + background-color: transparent; + border: none; + cursor: pointer; + height: 30px; + outline: 0; + width: 30px; + vertical-align: bottom +} + +.pell-button-selected { + background-color: #f0f0f0 +} + #debug { font-size: 1px; opacity: .8; diff --git a/index.html b/index.html index e66b78d3..f63d3c73 100644 --- a/index.html +++ b/index.html @@ -3211,10 +3211,7 @@ Object name:
-
- Note:
- -
+
@@ -3673,7 +3670,7 @@ @@ -3209,7 +3209,7 @@ Select object: Object name: - +
diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 66a4fa51..0ef3ad0c 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -526,7 +526,7 @@ function uploadMap(file, callback) { } else { load = true; message = `The map version (${mapVersion}) does not match the Generator version (${version}). -
The map will be auto-updated. In case of issues please keep using an ${archive} of the Generator`; +
Click OK to get map auto-updated. In case of issues please keep using an ${archive} of the Generator`; } alertMessage.innerHTML = message; $("#alert").dialog({title: "Version conflict", width: "38em", buttons: { From 044ea1d3453bba57dc7818e0792e3ffd0c4848c6 Mon Sep 17 00:00:00 2001 From: Evolvedexperiment Date: Fri, 26 Jun 2020 19:08:54 +0000 Subject: [PATCH 10/38] Added cell info to elevation profile and corrected some spelling --- index.html | 2 +- lang/lang-en.js | 4 ++-- main.js | 2 +- modules/burgs-and-states.js | 2 +- modules/cultures-generator.js | 2 +- modules/river-generator.js | 2 +- modules/routes-generator.js | 6 +++--- modules/ui/elevation-profile.js | 21 ++++++++++++++++++++- modules/ui/tools.js | 2 +- 9 files changed, 31 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index 60f463c9..635a1f37 100644 --- a/index.html +++ b/index.html @@ -3023,7 +3023,7 @@
Neutral
Suspicion
Enemy
-
Unknown
+
Unknown
Rival
Vassal
Suzerain
diff --git a/lang/lang-en.js b/lang/lang-en.js index 2ef89bbd..d4da51a9 100644 --- a/lang/lang-en.js +++ b/lang/lang-en.js @@ -355,7 +355,7 @@ const sourceDataForReference = { NeedToAdd!: "Neutral means states relations are neither positive nor negative", NeedToAdd!: "Suspicion means shate has a cautious distrust of another state", NeedToAdd!: "Enemies are states at war with each other", - NeedToAdd!: "Relations are unknown if states do not have enought information about each other", + NeedToAdd!: "Relations are unknown if states do not have enough information about each other", NeedToAdd!: "Rivalry is a state of competing for dominance in the region", NeedToAdd!: "Vassal is a state having obligation to its suzerain", NeedToAdd!: "Suzerain is a state having some control over its vassals", @@ -508,4 +508,4 @@ const sourceDataForReference = { NeedToAdd!: "Load .map file from local disk", NeedToAdd!: "Load .map file from URL (server should allow CORS)", NeedToAdd!: "Load map from browser storage (if saved before)" -}; \ No newline at end of file +}; diff --git a/main.js b/main.js index cd76e80b..eb4c4715 100644 --- a/main.js +++ b/main.js @@ -785,7 +785,7 @@ function generatePrecipitation() { let westerly = [], easterly = [], southerly = 0, northerly = 0; {// latitude bands - // x4 = 0-5 latitude: wet throught the year (rising zone) + // x4 = 0-5 latitude: wet through the year (rising zone) // x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone) // x1 = 20-30 latitude: dry all year (sinking zone) // x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone) diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 1fb2d9b5..1d940653 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -42,7 +42,7 @@ if (sorted.length < count * 10) { count = Math.floor(sorted.length / 10); if (!count) {console.warn(`There is no populated cells. Cannot generate states`); return burgs;} - else {console.warn(`Not enought populated cells (${sorted.length}). Will generate only ${count} states`);} + else {console.warn(`Not enough populated cells (${sorted.length}). Will generate only ${count} states`);} } let burgsTree = d3.quadtree(); diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index cf18c94b..fa2cb253 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -27,7 +27,7 @@ }); return; } else { - console.warn(`Not enought populated cells (${populated.length}). Will generate only ${count} cultures`); + console.warn(`Not enough populated cells (${populated.length}). Will generate only ${count} cultures`); alertMessage.innerHTML = ` There are only ${populated.length} populated cells and it's insufficient livable area.
Only ${count} out of ${culturesInput.value} requested cultures will be generated.
diff --git a/modules/river-generator.js b/modules/river-generator.js index 3431aca7..bef47df6 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -56,7 +56,7 @@ //const min = cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell let min = cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell - // allow only one river can flow thought a lake + // allow only one river can flow through a lake const cf = features[cells.f[i]]; // current cell feature if (cf.river && cf.river !== cells.r[i]) { cells.fl[i] = 0; diff --git a/modules/routes-generator.js b/modules/routes-generator.js index e02c4a6f..af45dc4e 100644 --- a/modules/routes-generator.js +++ b/modules/routes-generator.js @@ -8,7 +8,7 @@ console.time("generateMainRoads"); const cells = pack.cells, burgs = pack.burgs.filter(b => b.i && !b.removed); const capitals = burgs.filter(b => b.capital); - if (capitals.length < 2) return []; // not enought capitals to build main roads + if (capitals.length < 2) return []; // not enough capitals to build main roads const paths = []; // array to store path segments for (const b of capitals) { @@ -28,7 +28,7 @@ const getTrails = function() { console.time("generateTrails"); const cells = pack.cells, burgs = pack.burgs.filter(b => b.i && !b.removed); - if (burgs.length < 2) return []; // not enought burgs to build trails + if (burgs.length < 2) return []; // not enough burgs to build trails let paths = []; // array to store path segments for (const f of pack.features.filter(f => f.land)) { @@ -243,4 +243,4 @@ return [from, exit, false]; } -}))); \ No newline at end of file +}))); diff --git a/modules/ui/elevation-profile.js b/modules/ui/elevation-profile.js index 995f0270..f8b40d29 100644 --- a/modules/ui/elevation-profile.js +++ b/modules/ui/elevation-profile.js @@ -196,7 +196,26 @@ function showElevationProfile(data, routeLen, isRiver) { const x = chartData.points[k][0]; const y = yOffset + chartHeight; const c = biomesData.color[chartData.biome[k]]; - const dataTip = biomesData.name[chartData.biome[k]]+" (" + chartData.height[k] + " " + hu + ", cell " + chartData.cell[k] + ")"; + + const cell = chartData.cell[k]; + const culture = pack.cells.culture[cell]; + const religion = pack.cells.religion[cell]; + const province = pack.cells.province[cell]; + const state = pack.cells.state[cell]; + let pop = pack.cells.pop[cell]; + if (chartData.burg[k]) { + pop += pack.burgs[chartData.burg[k]].population * urbanization.value; + } + + const populationDesc = rn(pop * populationRate.value); + + const provinceDesc = province ? ", " + pack.provinces[province].name : ""; + const dataTip = biomesData.name[chartData.biome[k]] + + provinceDesc + + ", " + pack.states[state].name + + ", " + pack.religions[religion].name + + ", " + pack.cultures[culture].name + + " (height: " + chartData.height[k] + " " + hu + ", population " + populationDesc + ", cell " + chartData.cell[k] + ")"; g.append("rect").attr("stroke", c).attr("fill", c).attr("x", x).attr("y", y).attr("width", xscale(1)).attr("height", 15).attr("data-tip", dataTip); } diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 357163b3..a72800f5 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -155,7 +155,7 @@ function regenerateStates() { return; } if (burgs.length < +regionsInput.value) { - tip(`Not enought burgs to generate ${regionsInput.value} states. Will generate only ${burgs.length} states`, false, "warn"); + tip(`Not enough burgs to generate ${regionsInput.value} states. Will generate only ${burgs.length} states`, false, "warn"); } // burg local ids sorted by a bit randomized population: From 0e5388c7f5f6b0c97a66bedeffd2443a90c38fb3 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 4 Jul 2020 00:05:49 +0300 Subject: [PATCH 11/38] v1.4.38 --- index.css | 1 - 1 file changed, 1 deletion(-) diff --git a/index.css b/index.css index 3b577177..948b66d5 100644 --- a/index.css +++ b/index.css @@ -1854,7 +1854,6 @@ div#notes { background: rgba(255, 250, 228, 0.7); box-shadow: 2px 2px 5px -3px #3a2804; white-space: pre-line; - pointer-events: none; } div#notesHeader { From 43b3c8b8074ab7e6de60a813c939f00bb2c233b8 Mon Sep 17 00:00:00 2001 From: mdirienzo Date: Sat, 18 Jul 2020 04:31:09 -0400 Subject: [PATCH 12/38] Add the ability to regenerate cultures (#495) * Add the ability to regenerate cultures - Added a button to the tools menu for regeneration. - Regeneration button will handle initial generation of cultures and expansion afterwards. - Pressing regenerate will warn the user. - Small cleanup of trailing whitespace. * Refreshing cultures editor updates culture centers * Regenerating cultures refreshes the culture editor * Added a function to refresh all open editors * Reset burg and state cultures after regeneration * Address the problem of potential data loss Any errors while iterating the states or burgs could potentially lose the index 0 metadata stored in the arrays. This will instead track the index and ignore the 0th result. * Religions update cultures on culture regeneration Updated function names to be more similar and more descriptive --- index.html | 5 +++-- modules/burgs-and-states.js | 28 +++++++++++++++++++++++++++- modules/religions-generator.js | 13 ++++++++++++- modules/ui/cultures-editor.js | 1 + modules/ui/editors.js | 13 +++++++++++++ modules/ui/tools.js | 16 +++++++++++++--- 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 635a1f37..f3774fda 100644 --- a/index.html +++ b/index.html @@ -1861,6 +1861,7 @@ + @@ -3456,7 +3457,7 @@
Rate 
War Alert 
- +
@@ -3486,7 +3487,7 @@
Name 
Total 
- +
diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 1d940653..4cc36e2d 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -353,6 +353,32 @@ console.timeEnd("normalizeStates"); } + // Resets the cultures of all burgs and states to their + // cell or center cell's (respectively) culture. + const updateCultures = function () { + console.time('updateCulturesForBurgsAndStates'); + + // Assign the culture associated with the burgs cell. + pack.burgs = pack.burgs.map( (burg, index) => { + // Ignore metadata burg + if(index === 0) { + return burg; + } + return {...burg, culture: pack.cells.culture[burg.cell]}; + }); + + // Assign the culture associated with the states' center cell. + pack.states = pack.states.map( (state, index) => { + // Ignore neutrals state + if(index === 0) { + return state; + } + return {...state, culture: pack.cells.culture[state.center]}; + }); + + console.timeEnd('updateCulturesForBurgsAndStates'); + } + // calculate and draw curved state labels for a list of states const drawStateLabels = function(list) { console.time("drawStateLabels"); @@ -1029,6 +1055,6 @@ return {generate, expandStates, normalizeStates, assignColors, drawBurgs, specifyBurgs, defineBurgFeatures, drawStateLabels, collectStatistics, - generateCampaigns, generateDiplomacy, defineStateForms, getFullName, generateProvinces}; + generateCampaigns, generateDiplomacy, defineStateForms, getFullName, generateProvinces, updateCultures}; }))); diff --git a/modules/religions-generator.js b/modules/religions-generator.js index 096b3260..90ee88ee 100644 --- a/modules/religions-generator.js +++ b/modules/religions-generator.js @@ -279,6 +279,17 @@ }); } + function updateCultures() { + console.time('updateCulturesForReligions'); + pack.religions = pack.religions.map( (religion, index) => { + if(index === 0) { + return religion; + } + return {...religion, culture: pack.cells.culture[religion.center]}; + }); + console.timeEnd('updateCulturesForReligions'); + } + // assign a unique two-letters code (abbreviation) function getCode(rawName) { const name = rawName.replace("Old ", ""); // remove Old prefix @@ -350,6 +361,6 @@ return type() + " of the " + generateMeaning(); }; - return {generate, add, getDeityName, expandReligions}; + return {generate, add, getDeityName, expandReligions, updateCultures}; }))); diff --git a/modules/ui/cultures-editor.js b/modules/ui/cultures-editor.js index 369083af..8c4e7965 100644 --- a/modules/ui/cultures-editor.js +++ b/modules/ui/cultures-editor.js @@ -38,6 +38,7 @@ function editCultures() { function refreshCulturesEditor() { culturesCollectStatistics(); culturesEditorAddLines(); + drawCultureCenters(); } function culturesCollectStatistics() { diff --git a/modules/ui/editors.js b/modules/ui/editors.js index e858beaf..6129dd59 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -630,4 +630,17 @@ function selectIcon(initial, callback) { Apply: function() {callback(input.value||"⠀"); $(this).dialog("close")}, Close: function() {callback(initial); $(this).dialog("close")}} }); +} + +// Calls the refresh functionality on all editors currently open. +function refreshAllEditors() { + console.time('refreshAllEditors'); + if (document.getElementById('culturesEditorRefresh').offsetParent) culturesEditorRefresh.click(); + if (document.getElementById('biomesEditorRefresh').offsetParent) biomesEditorRefresh.click(); + if (document.getElementById('diplomacyEditorRefresh').offsetParent) diplomacyEditorRefresh.click(); + if (document.getElementById('provincesEditorRefresh').offsetParent) provincesEditorRefresh.click(); + if (document.getElementById('religionsEditorRefresh').offsetParent) religionsEditorRefresh.click(); + if (document.getElementById('statesEditorRefresh').offsetParent) statesEditorRefresh.click(); + if (document.getElementById('zonesEditorRefresh').offsetParent) zonesEditorRefresh.click(); + console.timeEnd('refreshAllEditors'); } \ No newline at end of file diff --git a/modules/ui/tools.js b/modules/ui/tools.js index a72800f5..066eda0b 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -55,15 +55,16 @@ toolsContent.addEventListener("click", function(event) { }); function processFeatureRegeneration(event, button) { - if (button === "regenerateStateLabels") {BurgsAndStates.drawStateLabels(); if (!layerIsOn("toggleLabels")) toggleLabels();} else - if (button === "regenerateReliefIcons") {ReliefIcons(); if (!layerIsOn("toggleRelief")) toggleRelief();} else - if (button === "regenerateRoutes") {Routes.regenerate(); if (!layerIsOn("toggleRoutes")) toggleRoutes();} else + if (button === "regenerateStateLabels") {BurgsAndStates.drawStateLabels(); if (!layerIsOn("toggleLabels")) toggleLabels();} else + if (button === "regenerateReliefIcons") {ReliefIcons(); if (!layerIsOn("toggleRelief")) toggleRelief();} else + if (button === "regenerateRoutes") {Routes.regenerate(); if (!layerIsOn("toggleRoutes")) toggleRoutes();} else if (button === "regenerateRivers") regenerateRivers(); else if (button === "regeneratePopulation") recalculatePopulation(); else if (button === "regenerateBurgs") regenerateBurgs(); else if (button === "regenerateStates") regenerateStates(); else if (button === "regenerateProvinces") regenerateProvinces(); else if (button === "regenerateReligions") regenerateReligions(); else + if (button === "regenerateCultures") regenerateCultures(); else if (button === "regenerateMilitary") regenerateMilitary(); else if (button === "regenerateIce") regenerateIce(); else if (button === "regenerateMarkers") regenerateMarkers(event); else @@ -244,6 +245,15 @@ function regenerateReligions() { if (!layerIsOn("toggleReligions")) toggleReligions(); else drawReligions(); } +function regenerateCultures() { + Cultures.generate(); + Cultures.expand(); + BurgsAndStates.updateCultures(); + Religions.updateCultures(); + if (!layerIsOn("toggleCultures")) toggleCultures(); else drawCultures(); + refreshAllEditors(); +} + function regenerateMilitary() { Military.generate(); if (!layerIsOn("toggleMilitary")) toggleMilitary(); From 5f4790c14175096970956e8bfed0cf76ea78882e Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 18 Jul 2020 11:36:48 +0300 Subject: [PATCH 13/38] v1.4.39 --- modules/ui/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index 72e39b21..d2b0ee1e 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -71,7 +71,7 @@ document.getElementById("options").querySelector("div.tab").addEventListener("cl // show popup with a list of Patreon supportes (updated manually, to be replaced with API call) function showSupporters() { - const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix"; + const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai"; alertMessage.innerHTML = "
    " + supporters.split(", ").sort().map(n => `
  • ${n}
  • `).join("") + "
"; $("#alert").dialog({resizable: false, title: "Patreon Supporters", width: "30vw", position: {my: "center", at: "center", of: "svg"}}); } From a9b16d6ee52d153bacf701a9dca6e38b4bd41dd0 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 6 Aug 2020 23:53:15 +0300 Subject: [PATCH 14/38] v1.4.40 --- modules/ui/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index d2b0ee1e..2779de69 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -71,7 +71,7 @@ document.getElementById("options").querySelector("div.tab").addEventListener("cl // show popup with a list of Patreon supportes (updated manually, to be replaced with API call) function showSupporters() { - const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai"; + const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai, Dell McKnight, Oneiris, Darinius Dragonclaw Studios, Christopher Whitney, Rhodes HvZ, Jeppe Skov Jensen, María Martín López, Martin Seeger, Annie Rishor, Aram Sabatés, MadNomadMedia"; alertMessage.innerHTML = "
    " + supporters.split(", ").sort().map(n => `
  • ${n}
  • `).join("") + "
"; $("#alert").dialog({resizable: false, title: "Patreon Supporters", width: "30vw", position: {my: "center", at: "center", of: "svg"}}); } From 460ccfeab7cea0c928409ee5edd1ee2edc3f4d9c Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Fri, 7 Aug 2020 11:21:26 +0200 Subject: [PATCH 15/38] Change filename format of saved files The following commit changes the default name of files saved by the user. Originally, any saved file was named ` D HH-mm.` Now filenames follow more closely ISO 8601 and are named by default ` YYYY-MM-DD-HH-mm.`. The function also became much smaller and easier to read. --- modules/ui/editors.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 6129dd59..1b8b83c1 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -546,12 +546,8 @@ function unfog(id) { function getFileName(dataType) { const name = mapName.value; const type = dataType ? dataType + " " : ""; - const date = new Date(); - const datFormatter = new Intl.DateTimeFormat("en", {month: "short", day: "numeric"}); - const timeFormatter = new Intl.DateTimeFormat("ru", {hour: "numeric", minute: "numeric"}); - const day = datFormatter.format(date).replace(" ", ""); - const time = timeFormatter.format(date).replace(":", "-"); - return name + " " + type + day + " " + time; + const dateString = new Date().toISOString().replace(/:[0-9]+\..*/, "").replaceAll(/[T:]/g, "-"); + return name + " " + type + dateString; } function downloadFile(data, name, type = "text/plain") { @@ -643,4 +639,4 @@ function refreshAllEditors() { if (document.getElementById('statesEditorRefresh').offsetParent) statesEditorRefresh.click(); if (document.getElementById('zonesEditorRefresh').offsetParent) zonesEditorRefresh.click(); console.timeEnd('refreshAllEditors'); -} \ No newline at end of file +} From 04a50992c905ef67a64ea0e930b3ddbfccbe1973 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 8 Aug 2020 02:10:27 +0300 Subject: [PATCH 16/38] v1.4.41 --- modules/ui/editors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 1b8b83c1..28c8a83f 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -546,7 +546,7 @@ function unfog(id) { function getFileName(dataType) { const name = mapName.value; const type = dataType ? dataType + " " : ""; - const dateString = new Date().toISOString().replace(/:[0-9]+\..*/, "").replaceAll(/[T:]/g, "-"); + const dateString = new Date().toISOString().replace(/:[0-9]+\..*/, "").replace(/[T:]/g, "-"); return name + " " + type + dateString; } From 0cceb31288f9e6c3c8bb638c07cf0152c5e7f66a Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Sat, 8 Aug 2020 20:50:26 +0200 Subject: [PATCH 17/38] =?UTF-8?q?Saved=20files=E2=80=99=20filename=20now?= =?UTF-8?q?=20holds=20local=20time=20(#505)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correcting PR #504, which made saved files’ filenames follow the UTC. This commit modifies the way the filename is generated and makes it follow the user’s local time. --- modules/ui/editors.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 28c8a83f..58e49370 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -544,9 +544,18 @@ function unfog(id) { } function getFileName(dataType) { + const formatTime = (time) => { + return (time < 10) ? "0" + time : time; + }; const name = mapName.value; const type = dataType ? dataType + " " : ""; - const dateString = new Date().toISOString().replace(/:[0-9]+\..*/, "").replace(/[T:]/g, "-"); + const date = new Date(); + const year = date.getFullYear(); + const month = formatTime(date.getMonth()); + const day = formatTime(date.getDay()); + const hour = formatTime(date.getHours()); + const minutes = formatTime(date.getMinutes()); + const dateString = [year, month, day, hour, minutes].join('-'); return name + " " + type + dateString; } From f17af04bafdfdab7e629f6f46a8390e8fa34c081 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 17 Aug 2020 21:37:16 +0300 Subject: [PATCH 18/38] v1.4.42 --- modules/river-generator.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/river-generator.js b/modules/river-generator.js index bef47df6..20ee34ba 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -253,6 +253,7 @@ const specify = function() { if (!pack.rivers.length) return; + Math.seedrandom(seed); const smallLength = pack.rivers.map(r => r.length||0).sort((a,b) => a-b)[Math.ceil(pack.rivers.length * .15)]; const smallType = {"Creek":9, "River":3, "Brook":3, "Stream":1}; // weighted small river types From 086a732895b8e9973a8c404b94590480470ffff6 Mon Sep 17 00:00:00 2001 From: evolvedexperiment <55178666+evolvedexperiment@users.noreply.github.com> Date: Thu, 20 Aug 2020 21:23:30 +0200 Subject: [PATCH 19/38] Fix for incorrect mapfile date (#510) --- modules/ui/editors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 58e49370..fba98560 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -551,8 +551,8 @@ function getFileName(dataType) { const type = dataType ? dataType + " " : ""; const date = new Date(); const year = date.getFullYear(); - const month = formatTime(date.getMonth()); - const day = formatTime(date.getDay()); + const month = formatTime(date.getMonth() + 1); + const day = formatTime(date.getDate()); const hour = formatTime(date.getHours()); const minutes = formatTime(date.getMinutes()); const dateString = [year, month, day, hour, minutes].join('-'); From d1d338877c4a5f387b41521d350737d858585d5e Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 20 Aug 2020 22:51:56 +0300 Subject: [PATCH 20/38] v1.4.43 --- index.html | 4 ++-- modules/ui/options.js | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index f3774fda..20586406 100644 --- a/index.html +++ b/index.html @@ -3651,8 +3651,8 @@

Generator uses pop-up window to download files. Please ensure your browser does not block popups

PNG / JPEG scale: - - + +
diff --git a/modules/ui/options.js b/modules/ui/options.js index 2779de69..60eed024 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -99,8 +99,6 @@ optionsContent.addEventListener("input", function(event) { else if (id === "uiSizeOutput") changeUIsize(value); else if (id === "tooltipSizeInput" || id === "tooltipSizeOutput") changeTooltipSize(value); else if (id === "transparencyInput") changeDialogsTransparency(value); - else if (id === "pngResolutionInput") pngResolutionOutput.value = value; - else if (id === "pngResolutionOutput") pngResolutionInput.value = value; }); optionsContent.addEventListener("change", function(event) { From 05f54ab9e187f7f42beb8513fbbd31b0ae308e33 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 8 Sep 2020 23:47:24 +0300 Subject: [PATCH 21/38] v1.4.44 --- modules/save-and-load.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 0ef3ad0c..6ad47701 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -154,6 +154,15 @@ function inlineStyle(clone) { style += key + ':' + value + ';'; } + for (const key in compStyle) { + const value = compStyle.getPropertyValue(key); + + if (key === "cursor") continue; // cursor should be default + if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute + if (value === defaultStyles.getPropertyValue(key)) continue; + style += key + ':' + value + ';'; + } + if (style != "") this.setAttribute('style', style); }); From 4f56f9f90e2b64b39fd59ace92245b4a59c1ae65 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 12 Oct 2020 11:32:52 +0300 Subject: [PATCH 22/38] v1.4.45 --- modules/ui/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index 60eed024..9d43ff1a 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -71,7 +71,7 @@ document.getElementById("options").querySelector("div.tab").addEventListener("cl // show popup with a list of Patreon supportes (updated manually, to be replaced with API call) function showSupporters() { - const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai, Dell McKnight, Oneiris, Darinius Dragonclaw Studios, Christopher Whitney, Rhodes HvZ, Jeppe Skov Jensen, María Martín López, Martin Seeger, Annie Rishor, Aram Sabatés, MadNomadMedia"; + const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai, Dell McKnight, Oneiris, Darinius Dragonclaw Studios, Christopher Whitney, Rhodes HvZ, Jeppe Skov Jensen, María Martín López, Martin Seeger, Annie Rishor, Aram Sabatés, MadNomadMedia, Eric Foley, Vito Martono, James H. Anthony, Kevin Cossutta, Thirty-OneR , ThatGuyGW , Dee Chiu, MontyBoosh , Achillain , Jaden , SashaTK, Steve Johnson"; alertMessage.innerHTML = "
    " + supporters.split(", ").sort().map(n => `
  • ${n}
  • `).join("") + "
"; $("#alert").dialog({resizable: false, title: "Patreon Supporters", width: "30vw", position: {my: "center", at: "center", of: "svg"}}); } From e480c1c8e503e5788e0344358440f8525114049a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9on?= Date: Mon, 19 Oct 2020 21:07:46 +0200 Subject: [PATCH 23/38] fix ReferenceError on changeViewMode (#528) --- modules/ui/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index 9d43ff1a..00797a84 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -509,7 +509,7 @@ document.getElementById("mapToLoad").addEventListener("change", function() { // View mode viewMode.addEventListener("click", changeViewMode); -function changeViewMode() { +function changeViewMode(event) { const button = event.target; if (button.tagName !== "BUTTON") return; const pressed = button.classList.contains("pressed"); From f4efedcf9d2745b815e208433fa2adf4b00dd385 Mon Sep 17 00:00:00 2001 From: Bryce Kabat Date: Wed, 21 Oct 2020 17:32:57 -0500 Subject: [PATCH 24/38] Added Logging Options to Improve Performance (#529) * Added Logging Options to Improve Performance * Requested Changes Co-authored-by: Onyx Azryn --- main.js | 100 +++++++++++++++++---------------- modules/burgs-and-states.js | 64 ++++++++++----------- modules/cultures-generator.js | 14 ++--- modules/heightmap-generator.js | 6 +- modules/military-generator.js | 4 +- modules/names-generator.js | 14 ++--- modules/ocean-layers.js | 6 +- modules/relief-icons.js | 4 +- modules/religions-generator.js | 10 ++-- modules/river-generator.js | 4 +- modules/routes-generator.js | 16 +++--- modules/save-and-load.js | 46 +++++++-------- modules/ui/burg-editor.js | 2 +- modules/ui/editors.js | 6 +- modules/ui/heightmap-editor.js | 18 +++--- modules/ui/layers.js | 52 ++++++++--------- modules/ui/style.js | 2 +- modules/utils.js | 10 ++-- 18 files changed, 192 insertions(+), 186 deletions(-) diff --git a/main.js b/main.js index eb4c4715..3ab242d7 100644 --- a/main.js +++ b/main.js @@ -10,6 +10,12 @@ const version = "1.4"; // generator version document.title += " v" + version; +// Switches to disable/enable logging features +const INFO = 0; +const TIME = 0; +const WARN = 1; +const ERROR = 1; + // if map version is not stored, clear localStorage and show a message if (rn(localStorage.getItem("version"), 2) !== rn(version, 2)) { localStorage.clear(); @@ -142,7 +148,7 @@ void function checkLoadParameters() { // of there is a valid maplink, try to load .map file from URL if (params.get("maplink")) { - console.warn("Load map from URL"); + WARN && console.warn("Load map from URL"); const maplink = params.get("maplink"); const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; const valid = pattern.test(maplink); @@ -152,7 +158,7 @@ void function checkLoadParameters() { // if there is a seed (user of MFCG provided), generate map for it if (params.get("seed")) { - console.warn("Generate map for seed"); + WARN && console.warn("Generate map for seed"); generateMapOnLoad(); return; } @@ -161,24 +167,24 @@ void function checkLoadParameters() { if (onloadMap.value === "saved") { ldb.get("lastMap", blob => { if (blob) { - console.warn("Load last saved map"); + WARN && console.warn("Load last saved map"); try { uploadMap(blob); } catch(error) { - console.error(error); - console.warn("Cannot load stored map, random map to be generated"); + ERROR && console.error(error); + WARN && console.warn("Cannot load stored map, random map to be generated"); generateMapOnLoad(); } } else { - console.error("No map stored, random map to be generated"); + ERROR && console.error("No map stored, random map to be generated"); generateMapOnLoad(); } }); return; } - console.warn("Generate random map"); + WARN && console.warn("Generate random map"); generateMapOnLoad(); }() @@ -197,7 +203,7 @@ function loadMapFromURL(maplink, random) { } function showUploadErrorMessage(error, URL, random) { - console.error(error); + ERROR && console.error(error); alertMessage.innerHTML = `Cannot load map from the ${link(URL, "link provided")}. ${random?`A new random map is generated. `:''} Please ensure the linked file is reachable and CORS is allowed on server side`; @@ -249,7 +255,7 @@ function focusOn() { // find burg for MFCG and focus on it function findBurgForMFCG(params) { const cells = pack.cells, burgs = pack.burgs; - if (pack.burgs.length < 2) {console.error("Cannot select a burg for MFCG"); return;} + if (pack.burgs.length < 2) {ERROR && console.error("Cannot select a burg for MFCG"); return;} // used for selection const size = +params.get("size"); @@ -274,7 +280,7 @@ function findBurgForMFCG(params) { // select a burg with closest population from selection const selected = d3.scan(selection, (a, b) => Math.abs(a.population - size) - Math.abs(b.population - size)); const burgId = selection[selected].i; - if (!burgId) {console.error("Cannot select a burg for MFCG"); return;} + if (!burgId) {ERROR && console.error("Cannot select a burg for MFCG"); return;} const b = burgs[burgId]; const referrer = new URL(document.referrer); @@ -507,7 +513,7 @@ function generate() { const timeStart = performance.now(); invokeActiveZooming(); generateSeed(); - console.group("Generated Map " + seed); + INFO && console.group("Generated Map " + seed); applyMapSize(); randomizeOptions(); placePoints(); @@ -548,12 +554,12 @@ function generate() { addZones(); Names.getMapName(); - console.warn(`TOTAL: ${rn((performance.now()-timeStart)/1000,2)}s`); + WARN && console.warn(`TOTAL: ${rn((performance.now()-timeStart)/1000,2)}s`); showStatistics(); - console.groupEnd("Generated Map " + seed); + INFO && console.groupEnd("Generated Map " + seed); } catch(error) { - console.error(error); + ERROR && console.error(error); clearMainTip(); alertMessage.innerHTML = `An error is occured on map generation. Please retry. @@ -586,35 +592,35 @@ function generateSeed() { // Place points to calculate Voronoi diagram function placePoints() { - console.time("placePoints"); + TIME && console.time("placePoints"); const cellsDesired = 10000 * densityInput.value; // generate 10k points for each densityInput point const spacing = grid.spacing = rn(Math.sqrt(graphWidth * graphHeight / cellsDesired), 2); // spacing between points before jirrering grid.boundary = getBoundaryPoints(graphWidth, graphHeight, spacing); grid.points = getJitteredGrid(graphWidth, graphHeight, spacing); // jittered square grid grid.cellsX = Math.floor((graphWidth + 0.5 * spacing) / spacing); grid.cellsY = Math.floor((graphHeight + 0.5 * spacing) / spacing); - console.timeEnd("placePoints"); + TIME && console.timeEnd("placePoints"); } // calculate Delaunay and then Voronoi diagram function calculateVoronoi(graph, points) { - console.time("calculateDelaunay"); + TIME && console.time("calculateDelaunay"); const n = points.length; const allPoints = points.concat(grid.boundary); const delaunay = Delaunator.from(allPoints); - console.timeEnd("calculateDelaunay"); + TIME && console.timeEnd("calculateDelaunay"); - console.time("calculateVoronoi"); + TIME && console.time("calculateVoronoi"); const voronoi = Voronoi(delaunay, allPoints, n); graph.cells = voronoi.cells; graph.cells.i = n < 65535 ? Uint16Array.from(d3.range(n)) : Uint32Array.from(d3.range(n)); // array of indexes graph.vertices = voronoi.vertices; - console.timeEnd("calculateVoronoi"); + TIME && console.timeEnd("calculateVoronoi"); } // Mark features (ocean, lakes, islands) function markFeatures() { - console.time("markFeatures"); + TIME && console.time("markFeatures"); Math.seedrandom(seed); // restart Math.random() to get the same result on heightmap edit in Erase mode const cells = grid.cells, heights = grid.cells.h; cells.f = new Uint16Array(cells.i.length); // cell feature number @@ -648,7 +654,7 @@ function markFeatures() { queue[0] = cells.f.findIndex(f => !f); // find unmarked cell } - console.timeEnd("markFeatures"); + TIME && console.timeEnd("markFeatures"); } // How to handle lakes generated near seas? They can be both open or closed. @@ -658,7 +664,7 @@ function openNearSeaLakes() { if (templateInput.value === "Atoll") return; // no need for Atolls const cells = grid.cells, features = grid.features; if (!features.find(f => f.type === "lake")) return; // no lakes - console.time("openLakes"); + TIME && console.time("openLakes"); const limit = 50; // max height that can be breached by water for (let t = 0, removed = true; t < 5 && removed; t++) { @@ -694,7 +700,7 @@ function openNearSeaLakes() { return true; } - console.timeEnd("openLakes"); + TIME && console.timeEnd("openLakes"); } // define map size and position based on template and random factor @@ -745,7 +751,7 @@ function calculateMapCoordinates() { // temperature model function calculateTemperatures() { - console.time('calculateTemperatures'); + TIME && console.time('calculateTemperatures'); const cells = grid.cells; cells.temp = new Int8Array(cells.i.length); // temperature array @@ -771,12 +777,12 @@ function calculateTemperatures() { return rn(height / 1000 * 6.5); } - console.timeEnd('calculateTemperatures'); + TIME && console.timeEnd('calculateTemperatures'); } // simplest precipitation model function generatePrecipitation() { - console.time('generatePrecipitation'); + TIME && console.time('generatePrecipitation'); prec.selectAll("*").remove(); const cells = grid.cells; cells.prec = new Uint8Array(cells.i.length); // precipitation array @@ -887,12 +893,12 @@ function generatePrecipitation() { if (southerly) wind.append("text").attr("x", graphWidth / 2).attr("y", graphHeight - 20).text("\u21C8"); }(); - console.timeEnd('generatePrecipitation'); + TIME && console.timeEnd('generatePrecipitation'); } // recalculate Voronoi Graph to pack cells function reGraph() { - console.time("reGraph"); + TIME && console.time("reGraph"); let cells = grid.cells, points = grid.points, features = grid.features; const newCells = {p:[], g:[], h:[], t:[], f:[], r:[], biome:[]}; // to store new data const spacing2 = grid.spacing ** 2; @@ -936,12 +942,12 @@ function reGraph() { cells.area = new Uint16Array(cells.i.length); // cell area cells.i.forEach(i => cells.area[i] = Math.abs(d3.polygonArea(getPackPolygon(i)))); - console.timeEnd("reGraph"); + TIME && console.timeEnd("reGraph"); } // Detect and draw the coasline function drawCoastline() { - console.time('drawCoastline'); + TIME && console.time('drawCoastline'); reMarkFeatures(); const cells = pack.cells, vertices = pack.vertices, n = cells.i.length, features = pack.features; const used = new Uint8Array(features.length); // store conneted features @@ -1016,7 +1022,7 @@ function drawCoastline() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length-1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length-1]) {ERROR && console.error("Next vertex is not found"); break;} } //chain.push(chain[0]); // push first vertex as the last one return chain; @@ -1040,12 +1046,12 @@ function drawCoastline() { } } - console.timeEnd('drawCoastline'); + TIME && console.timeEnd('drawCoastline'); } // Re-mark features (ocean, lakes, islands) function reMarkFeatures() { - console.time("reMarkFeatures"); + TIME && console.time("reMarkFeatures"); const cells = pack.cells, features = pack.features = [0], temp = grid.cells.temp; cells.f = new Uint16Array(cells.i.length); // cell feature number cells.t = new Int16Array(cells.i.length); // cell type: 1 = land along coast; -1 = water along coast; @@ -1113,13 +1119,13 @@ function reMarkFeatures() { return "isle"; } - console.timeEnd("reMarkFeatures"); + TIME && console.timeEnd("reMarkFeatures"); } // temporary elevate some lakes to resolve depressions and flux the water to form an open (exorheic) lake function elevateLakes() { if (templateInput.value === "Atoll") return; // no need for Atolls - console.time('elevateLakes'); + TIME && console.time('elevateLakes'); const cells = pack.cells, features = pack.features; const maxCells = cells.i.length / 100; // size limit; let big lakes be closed (endorheic) cells.i.forEach(i => { @@ -1129,12 +1135,12 @@ function elevateLakes() { //debug.append("circle").attr("cx", cells.p[i][0]).attr("cy", cells.p[i][1]).attr("r", .5).attr("fill", "blue"); }); - console.timeEnd('elevateLakes'); + TIME && console.timeEnd('elevateLakes'); } // assign biome id for each cell function defineBiomes() { - console.time("defineBiomes"); + TIME && console.time("defineBiomes"); const cells = pack.cells, f = pack.features, temp = grid.cells.temp, prec = grid.cells.prec; cells.biome = new Uint8Array(cells.i.length); // biomes array @@ -1153,7 +1159,7 @@ function defineBiomes() { return rn(4 + d3.mean(n)); } - console.timeEnd("defineBiomes"); + TIME && console.timeEnd("defineBiomes"); } // assign biome id to a cell @@ -1168,7 +1174,7 @@ function getBiomeId(moisture, temperature, height) { // assess cells suitability to calculate population and rand cells for culture center and burgs placement function rankCells() { - console.time('rankCells'); + TIME && console.time('rankCells'); const cells = pack.cells, f = pack.features; cells.s = new Int16Array(cells.i.length); // cell suitability array cells.pop = new Float32Array(cells.i.length); // cell population array @@ -1202,13 +1208,13 @@ function rankCells() { cells.pop[i] = cells.s[i] > 0 ? cells.s[i] * cells.area[i] / areaMean : 0; } - console.timeEnd('rankCells'); + TIME && console.timeEnd('rankCells'); } // generate some markers function addMarkers(number = 1) { if (!number) return; - console.time("addMarkers"); + TIME && console.time("addMarkers"); const cells = pack.cells, states = pack.states; void function addVolcanoes() { @@ -1374,12 +1380,12 @@ function addMarkers(number = 1) { return id; } - console.timeEnd("addMarkers"); + TIME && console.timeEnd("addMarkers"); } // regenerate some zones function addZones(number = 1) { - console.time("addZones"); + TIME && console.time("addZones"); const data = [], cells = pack.cells, states = pack.states, burgs = pack.burgs; const used = new Uint8Array(cells.i.length); // to store used cells @@ -1690,7 +1696,7 @@ function addZones(number = 1) { .attr("points", d => getPackPolygon(d)).attr("id", function(d) {return this.parentNode.id+"_"+d}); }() - console.timeEnd("addZones"); + TIME && console.timeEnd("addZones"); } // show map stats on generation complete @@ -1712,11 +1718,11 @@ function showStatistics() { mapId = Date.now(); // unique map id is it's creation date number mapHistory.push({seed, width:graphWidth, height:graphHeight, template, created:mapId}); - console.log(stats); + INFO && console.log(stats); } const regenerateMap = debounce(function() { - console.warn("Generate new random map"); + WARN && console.warn("Generate new random map"); closeDialogs("#worldConfigurator, #options3d"); customization = 0; undraw(); diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 4cc36e2d..bbb48e4f 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -32,7 +32,7 @@ drawBurgs(); function placeCapitals() { - console.time('placeCapitals'); + TIME && console.time('placeCapitals'); let count = +regionsInput.value; let burgs = [0]; @@ -41,8 +41,8 @@ if (sorted.length < count * 10) { count = Math.floor(sorted.length / 10); - if (!count) {console.warn(`There is no populated cells. Cannot generate states`); return burgs;} - else {console.warn(`Not enough populated cells (${sorted.length}). Will generate only ${count} states`);} + if (!count) {WARN && console.warn(`There is no populated cells. Cannot generate states`); return burgs;} + else {WARN && console.warn(`Not enough populated cells (${sorted.length}). Will generate only ${count} states`);} } let burgsTree = d3.quadtree(); @@ -57,20 +57,20 @@ } if (i === sorted.length - 1) { - console.warn("Cannot place capitals with current spacing. Trying again with reduced spacing"); + WARN && console.warn("Cannot place capitals with current spacing. Trying again with reduced spacing"); burgsTree = d3.quadtree(); i = -1, burgs = [0], spacing /= 1.2; } } burgs[0] = burgsTree; - console.timeEnd('placeCapitals'); + TIME && console.timeEnd('placeCapitals'); return burgs; } // For each capital create a state function createStates() { - console.time('createStates'); + TIME && console.time('createStates'); const states = [{i:0, name: "Neutrals"}]; const colors = getColors(burgs.length-1); @@ -94,13 +94,13 @@ cells.burg[b.cell] = i; }); - console.timeEnd('createStates'); + TIME && console.timeEnd('createStates'); return states; } // place secondary settlements based on geo and economical evaluation function placeTowns() { - console.time('placeTowns'); + TIME && console.time('placeTowns'); const score = new Int16Array(cells.s.map(s => s * gauss(1,3,0,20,3))); // a bit randomized cell score for towns placement const sorted = cells.i.filter(i => !cells.burg[i] && score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes @@ -129,17 +129,17 @@ } if (manorsInput.value != 1000 && burgsAdded < desiredNumber) { - console.error(`Cannot place all burgs. Requested ${desiredNumber}, placed ${burgsAdded}`); + ERROR && console.error(`Cannot place all burgs. Requested ${desiredNumber}, placed ${burgsAdded}`); } burgs[0] = {name:undefined}; // do not store burgsTree anymore - console.timeEnd('placeTowns'); + TIME && console.timeEnd('placeTowns'); } } // define burg coordinates, port status and define details const specifyBurgs = function() { - console.time("specifyBurgs"); + TIME && console.time("specifyBurgs"); const cells = pack.cells, vertices = pack.vertices, features = pack.features, temp = grid.cells.temp; for (const b of pack.burgs) { @@ -185,7 +185,7 @@ if (featurePorts.length === 1) featurePorts[0].port = 0; } - console.timeEnd("specifyBurgs"); + TIME && console.timeEnd("specifyBurgs"); } const defineBurgFeatures = function(newburg) { @@ -202,7 +202,7 @@ } const drawBurgs = function() { - console.time("drawBurgs"); + TIME && console.time("drawBurgs"); // remove old data burgIcons.selectAll("circle").remove(); @@ -251,12 +251,12 @@ .attr("x", d => rn(d.x - taSize * .47, 2)).attr("y", d => rn(d.y - taSize * .47, 2)) .attr("width", taSize).attr("height", taSize); - console.timeEnd("drawBurgs"); + TIME && console.timeEnd("drawBurgs"); } // growth algorithm to assign cells to states like we did for cultures const expandStates = function() { - console.time("expandStates"); + TIME && console.time("expandStates"); const cells = pack.cells, states = pack.states, cultures = pack.cultures, burgs = pack.burgs; cells.state = new Uint16Array(cells.i.length); // cell state @@ -331,11 +331,11 @@ return 0; } - console.timeEnd("expandStates"); + TIME && console.timeEnd("expandStates"); } const normalizeStates = function() { - console.time("normalizeStates"); + TIME && console.time("normalizeStates"); const cells = pack.cells, burgs = pack.burgs; for (const i of cells.i) { @@ -350,13 +350,13 @@ cells.state[i] = cells.state[adversaries[0]]; //debug.append("circle").attr("cx", cells.p[i][0]).attr("cy", cells.p[i][1]).attr("r", .5).attr("fill", "red"); } - console.timeEnd("normalizeStates"); + TIME && console.timeEnd("normalizeStates"); } // Resets the cultures of all burgs and states to their // cell or center cell's (respectively) culture. const updateCultures = function () { - console.time('updateCulturesForBurgsAndStates'); + TIME && console.time('updateCulturesForBurgsAndStates'); // Assign the culture associated with the burgs cell. pack.burgs = pack.burgs.map( (burg, index) => { @@ -376,12 +376,12 @@ return {...state, culture: pack.cells.culture[state.center]}; }); - console.timeEnd('updateCulturesForBurgsAndStates'); + TIME && console.timeEnd('updateCulturesForBurgsAndStates'); } // calculate and draw curved state labels for a list of states const drawStateLabels = function(list) { - console.time("drawStateLabels"); + TIME && console.time("drawStateLabels"); const cells = pack.cells, features = pack.features, states = pack.states; const paths = []; // text paths lineGen.curve(d3.curveBundle.beta(1)); @@ -563,12 +563,12 @@ if (!displayed) toggleLabels(); }() - console.timeEnd("drawStateLabels"); + TIME && console.timeEnd("drawStateLabels"); } // calculate states data like area, population etc. const collectStatistics = function() { - console.time("collectStatistics"); + TIME && console.time("collectStatistics"); const cells = pack.cells, states = pack.states; states.forEach(s => { s.cells = s.area = s.burgs = s.rural = s.urban = 0; @@ -595,11 +595,11 @@ // convert neighbors Set object into array states.forEach(s => s.neighbors = Array.from(s.neighbors)); - console.timeEnd("collectStatistics"); + TIME && console.timeEnd("collectStatistics"); } const assignColors = function() { - console.time("assignColors"); + TIME && console.time("assignColors"); const colors = ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f"]; // d3.schemeSet2; // assin basic color using greedy coloring algorithm @@ -620,7 +620,7 @@ }); }); - console.timeEnd("assignColors"); + TIME && console.timeEnd("assignColors"); } // generate historical conflicts of each state @@ -641,7 +641,7 @@ // generate Diplomatic Relationships const generateDiplomacy = function() { - console.time("generateDiplomacy"); + TIME && console.time("generateDiplomacy"); const cells = pack.cells, states = pack.states; const chronicle = states[0].diplomacy = []; const valid = states.filter(s => s.i && !states.removed); @@ -782,13 +782,13 @@ chronicle.push(war); // add a record to diplomatical history } - console.timeEnd("generateDiplomacy"); + TIME && console.timeEnd("generateDiplomacy"); //console.table(states.map(s => s.diplomacy)); } // select a forms for listed or all valid states const defineStateForms = function(list) { - console.time("defineStateForms"); + TIME && console.time("defineStateForms"); const states = pack.states.filter(s => s.i && !s.removed); if (states.length < 1) return; @@ -878,7 +878,7 @@ } } - console.timeEnd("defineStateForms"); + TIME && console.timeEnd("defineStateForms"); } const getFullName = function(s) { @@ -890,7 +890,7 @@ } const generateProvinces = function(regenerate) { - console.time("generateProvinces"); + TIME && console.time("generateProvinces"); const localSeed = regenerate ? Math.floor(Math.random() * 1e9).toString() : seed; Math.seedrandom(localSeed); @@ -1050,7 +1050,7 @@ } }); - console.timeEnd("generateProvinces"); + TIME && console.timeEnd("generateProvinces"); } return {generate, expandStates, normalizeStates, assignColors, diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index fa2cb253..8e05018f 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -7,7 +7,7 @@ let cells; const generate = function() { - console.time('generateCultures'); + TIME && console.time('generateCultures'); cells = pack.cells; cells.culture = new Uint16Array(cells.i.length); // cell cultures let count = Math.min(+culturesInput.value, +culturesSet.selectedOptions[0].dataset.max); @@ -16,7 +16,7 @@ if (populated.length < count * 25) { count = Math.floor(populated.length / 50); if (!count) { - console.warn(`There are no populated cells. Cannot generate cultures`); + WARN && console.warn(`There are no populated cells. Cannot generate cultures`); pack.cultures = [{name:"Wildlands", i:0, base:1}]; alertMessage.innerHTML = ` The climate is harsh and people cannot live in this world.
@@ -27,7 +27,7 @@ }); return; } else { - console.warn(`Not enough populated cells (${populated.length}). Will generate only ${count} cultures`); + WARN && console.warn(`Not enough populated cells (${populated.length}). Will generate only ${count} cultures`); alertMessage.innerHTML = ` There are only ${populated.length} populated cells and it's insufficient livable area.
Only ${count} out of ${culturesInput.value} requested cultures will be generated.
@@ -68,7 +68,7 @@ cultures.unshift({name:"Wildlands", i:0, base:1, origin:null}); // make sure all bases exist in nameBases - if (!nameBases.length) {console.error("Name base is empty, default nameBases will be applied"); nameBases = Names.getNameBases();} + if (!nameBases.length) {ERROR && console.error("Name base is empty, default nameBases will be applied"); nameBases = Names.getNameBases();} cultures.forEach(c => c.base = c.base % nameBases.length); function getRandomCultures(c) { @@ -108,7 +108,7 @@ return rn((Math.random() * powerInput.value / 2 + 1) * base, 1); } - console.timeEnd('generateCultures'); + TIME && console.timeEnd('generateCultures'); } // assign a unique two-letters code (abbreviation) @@ -355,7 +355,7 @@ // expand cultures across the map (Dijkstra-like algorithm) const expand = function() { - console.time('expandCultures'); + TIME && console.time('expandCultures'); cells = pack.cells; const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); @@ -392,7 +392,7 @@ }); } //debug.selectAll(".text").data(cost).enter().append("text").attr("x", (d, e) => cells.p[e][0]-1).attr("y", (d, e) => cells.p[e][1]-1).text(d => d ? rn(d) : "").attr("font-size", 2); - console.timeEnd('expandCultures'); + TIME && console.timeEnd('expandCultures'); } function getBiomeCost(c, biome, type) { diff --git a/modules/heightmap-generator.js b/modules/heightmap-generator.js index dc2cf52b..e469b4dc 100644 --- a/modules/heightmap-generator.js +++ b/modules/heightmap-generator.js @@ -7,7 +7,7 @@ let cells, p; const generate = function() { - console.time('generateHeightmap'); + TIME && console.time('generateHeightmap'); cells = grid.cells, p = grid.points; cells.h = new Uint8Array(grid.points.length); @@ -25,7 +25,7 @@ case "Shattered": templateShattered(); break; } - console.timeEnd('generateHeightmap'); + TIME && console.timeEnd('generateHeightmap'); } // parse template step @@ -507,7 +507,7 @@ } function getPointInRange(range, length) { - if (typeof range !== "string") {console.error("Range should be a string"); return;} + if (typeof range !== "string") {ERROR && console.error("Range should be a string"); return;} const min = range.split("-")[0]/100 || 0; const max = range.split("-")[1]/100 || 100; return rand(min * length, max * length); diff --git a/modules/military-generator.js b/modules/military-generator.js index a4b578e6..4dd19d3f 100644 --- a/modules/military-generator.js +++ b/modules/military-generator.js @@ -7,7 +7,7 @@ let cells, p, states; const generate = function() { - console.time("generateMilitaryForces"); + TIME && console.time("generateMilitaryForces"); cells = pack.cells, p = cells.p, states = pack.states; const valid = states.filter(s => s.i && !s.removed); // valid states if (!options.military) options.military = getDefaultOptions(); @@ -176,7 +176,7 @@ return regiments; } - console.timeEnd("generateMilitaryForces"); + TIME && console.timeEnd("generateMilitaryForces"); } const getDefaultOptions = function() { diff --git a/modules/names-generator.js b/modules/names-generator.js index 98776011..32367be1 100644 --- a/modules/names-generator.js +++ b/modules/names-generator.js @@ -56,13 +56,13 @@ // generate name using Markov's chain const getBase = function(base, min, max, dupl) { - if (base === undefined) {console.error("Please define a base"); return;} + if (base === undefined) {ERROR && console.error("Please define a base"); return;} if (!chains[base]) updateChain(base); const data = chains[base]; if (!data || data[""] === undefined) { tip("Namesbase " + base + " is incorrect. Please check in namesbase editor", false, "error"); - console.error("Namebase " + base + " is incorrect!"); + ERROR && console.error("Namebase " + base + " is incorrect!"); return "ERROR"; } @@ -106,7 +106,7 @@ if (name.split(" ").some(part => part.length < 2)) name = name.split(" ").map((p,i) => i ? p.toLowerCase() : p).join(""); if (name.length < 2) { - console.error("Name is too short! Random name will be selected"); + ERROR && console.error("Name is too short! Random name will be selected"); name = ra(nameBases[base].b.split(",")); } @@ -115,14 +115,14 @@ // generate name for culture const getCulture = function(culture, min, max, dupl) { - if (culture === undefined) {console.error("Please define a culture"); return;} + if (culture === undefined) {ERROR && console.error("Please define a culture"); return;} const base = pack.cultures[culture].base; return getBase(base, min, max, dupl); } // generate short name for culture const getCultureShort = function(culture) { - if (culture === undefined) {console.error("Please define a culture"); return;} + if (culture === undefined) {ERROR && console.error("Please define a culture"); return;} return getBaseShort(pack.cultures[culture].base); } @@ -139,8 +139,8 @@ // generate state name based on capital or random name and culture-specific suffix const getState = function(name, culture, base) { - if (name === undefined) {console.error("Please define a base name"); return;} - if (culture === undefined && base === undefined) {console.error("Please define a culture"); return;} + if (name === undefined) {ERROR && console.error("Please define a base name"); return;} + if (culture === undefined && base === undefined) {ERROR && console.error("Please define a culture"); return;} if (base === undefined) base = pack.cultures[culture].base; // exclude endings inappropriate for states name diff --git a/modules/ocean-layers.js b/modules/ocean-layers.js index b5be82f4..a39bbdd7 100644 --- a/modules/ocean-layers.js +++ b/modules/ocean-layers.js @@ -9,7 +9,7 @@ const OceanLayers = function OceanLayers() { const outline = oceanLayers.attr("layers"); if (outline === "none") return; - console.time("drawOceanLayers"); + TIME && console.time("drawOceanLayers"); lineGen.curve(d3.curveBasisClosed); cells = grid.cells, pointsN = grid.cells.i.length, vertices = grid.vertices; @@ -51,7 +51,7 @@ return cells.v[i][cells.c[i].findIndex(c => cells.t[c] < t || !cells.t[c])]; } - console.timeEnd("drawOceanLayers"); + TIME && console.timeEnd("drawOceanLayers"); } function randomizeOutline() { @@ -89,7 +89,7 @@ if (v[0] !== undefined && v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== undefined && v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== undefined && v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } chain.push(chain[0]); // push first vertex as the last one return chain; diff --git a/modules/relief-icons.js b/modules/relief-icons.js index 0d806e8b..ab1916ce 100644 --- a/modules/relief-icons.js +++ b/modules/relief-icons.js @@ -5,7 +5,7 @@ }(this, (function () {'use strict'; const ReliefIcons = function() { - console.time('drawRelief'); + TIME && console.time('drawRelief'); terrain.selectAll("*").remove(); const density = terrain.attr("density") || .4; const size = 1.6 * (terrain.attr("size") || 1); @@ -69,7 +69,7 @@ terrain.html(reliefHTML); }() - console.timeEnd('drawRelief'); + TIME && console.timeEnd('drawRelief'); } function getBiomeIcon(i, b) { diff --git a/modules/religions-generator.js b/modules/religions-generator.js index 90ee88ee..1563f966 100644 --- a/modules/religions-generator.js +++ b/modules/religions-generator.js @@ -54,7 +54,7 @@ }; const generate = function() { - console.time('generateReligions'); + TIME && console.time('generateReligions'); const cells = pack.cells, states = pack.states, cultures = pack.cultures; const religions = pack.religions = []; cells.religion = new Uint16Array(cells.culture); // cell religion; initially based on culture @@ -164,7 +164,7 @@ expandHeresies(); checkCenters(); - console.timeEnd('generateReligions'); + TIME && console.timeEnd('generateReligions'); } const add = function(center) { @@ -280,14 +280,14 @@ } function updateCultures() { - console.time('updateCulturesForReligions'); + TIME && console.time('updateCulturesForReligions'); pack.religions = pack.religions.map( (religion, index) => { if(index === 0) { return religion; } return {...religion, culture: pack.cells.culture[religion.center]}; }); - console.timeEnd('updateCulturesForReligions'); + TIME && console.timeEnd('updateCulturesForReligions'); } // assign a unique two-letters code (abbreviation) @@ -303,7 +303,7 @@ // get supreme deity name const getDeityName = function(culture) { - if (culture === undefined) {console.error("Please define a culture"); return;} + if (culture === undefined) {ERROR && console.error("Please define a culture"); return;} const meaning = generateMeaning(); const cultureName = Names.getCulture(culture, null, null, "", .8); return cultureName + ", The " + meaning; diff --git a/modules/river-generator.js b/modules/river-generator.js index 20ee34ba..078392e1 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -5,7 +5,7 @@ }(this, (function () {'use strict'; const generate = function(changeHeights = true) { - console.time('generateRivers'); + TIME && console.time('generateRivers'); Math.seedrandom(seed); const cells = pack.cells, p = cells.p, features = pack.features; @@ -136,7 +136,7 @@ // apply change heights as basic one if (changeHeights) cells.h = Uint8Array.from(h); - console.timeEnd('generateRivers'); + TIME && console.timeEnd('generateRivers'); } // depression filling algorithm (for a correct water flux modeling) diff --git a/modules/routes-generator.js b/modules/routes-generator.js index af45dc4e..d9d1905c 100644 --- a/modules/routes-generator.js +++ b/modules/routes-generator.js @@ -5,7 +5,7 @@ }(this, (function () {'use strict'; const getRoads = function() { - console.time("generateMainRoads"); + TIME && console.time("generateMainRoads"); const cells = pack.cells, burgs = pack.burgs.filter(b => b.i && !b.removed); const capitals = burgs.filter(b => b.capital); if (capitals.length < 2) return []; // not enough capitals to build main roads @@ -21,12 +21,12 @@ } cells.i.forEach(i => cells.s[i] += cells.road[i] / 2); // add roads to suitability score - console.timeEnd("generateMainRoads"); + TIME && console.timeEnd("generateMainRoads"); return paths; } const getTrails = function() { - console.time("generateTrails"); + TIME && console.time("generateTrails"); const cells = pack.cells, burgs = pack.burgs.filter(b => b.i && !b.removed); if (burgs.length < 2) return []; // not enough burgs to build trails @@ -55,12 +55,12 @@ }); } - console.timeEnd("generateTrails"); + TIME && console.timeEnd("generateTrails"); return paths; } const getSearoutes = function() { - console.time("generateSearoutes"); + TIME && console.time("generateSearoutes"); const allPorts = pack.burgs.filter(b => b.port > 0 && !b.removed); if (allPorts.length < 2) return []; @@ -93,12 +93,12 @@ }); - console.timeEnd("generateSearoutes"); + TIME && console.timeEnd("generateSearoutes"); return paths; } const draw = function(main, small, ocean) { - console.time("drawRoutes"); + TIME && console.time("drawRoutes"); const cells = pack.cells, burgs = pack.burgs; lineGen.curve(d3.curveCatmullRom.alpha(0.1)); @@ -133,7 +133,7 @@ return [x, y]; })), 1)); - console.timeEnd("drawRoutes"); + TIME && console.timeEnd("drawRoutes"); } const regenerate = function() { diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 6ad47701..7ee574a5 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -3,7 +3,7 @@ // download map as SVG async function saveSVG() { - console.time("saveSVG"); + TIME && console.time("saveSVG"); const url = await getMapURL("svg"); const link = document.createElement("a"); link.download = getFileName() + ".svg"; @@ -12,12 +12,12 @@ async function saveSVG() { link.click(); tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000); - console.timeEnd("saveSVG"); + TIME && console.timeEnd("saveSVG"); } // download map as PNG async function savePNG() { - console.time("savePNG"); + TIME && console.time("savePNG"); const url = await getMapURL("png"); const link = document.createElement("a"); @@ -43,12 +43,12 @@ async function savePNG() { }); } - console.timeEnd("savePNG"); + TIME && console.timeEnd("savePNG"); } // download map as JPEG async function saveJPEG() { - console.time("saveJPEG"); + TIME && console.time("saveJPEG"); const url = await getMapURL("png"); const canvas = document.createElement("canvas"); @@ -70,7 +70,7 @@ async function saveJPEG() { window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000); } - console.timeEnd("saveJPEG"); + TIME && console.timeEnd("saveJPEG"); } // parse map svg to object url @@ -228,7 +228,7 @@ function GFontToDataURI(url) { // prepare map data for saving function getMapData() { - console.time("createMapDataBlob"); + TIME && console.time("createMapDataBlob"); return new Promise(resolve => { const date = new Date(); @@ -283,7 +283,7 @@ function getMapData() { namesData, rivers].join("\r\n"); const blob = new Blob([data], {type: "text/plain"}); - console.timeEnd("createMapDataBlob"); + TIME && console.timeEnd("createMapDataBlob"); resolve(blob); }); @@ -448,7 +448,7 @@ function quickLoad() { loadMapPrompt(blob); } else { tip("No map stored. Save map to storage first", true, "error", 2000); - console.error("No map stored"); + ERROR && console.error("No map stored"); } }); } @@ -467,12 +467,12 @@ function loadMapPrompt(blob) { }); function loadLastSavedMap() { - console.warn("Load last saved map"); + WARN && console.warn("Load last saved map"); try { uploadMap(blob); } catch(error) { - console.error(error); + ERROR && console.error(error); tip("Cannot load last saved map", true, "error", 2000); } } @@ -564,7 +564,7 @@ function parseLoadedData(data) { mapId = params[6] ? +params[6] : Date.now(); }() - console.group("Loaded Map " + seed); + INFO && console.group("Loaded Map " + seed); void function parseSettings() { const settings = data[1].split("|"); @@ -1006,49 +1006,49 @@ function parseLoadedData(data) { invalidStates.forEach(s => { const invalidCells = cells.i.filter(i => cells.state[i] === s); invalidCells.forEach(i => cells.state[i] = 0); - console.error("Data Integrity Check. Invalid state", s, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid state", s, "is assigned to cells", invalidCells); }); const invalidProvinces = [...new Set(cells.province)].filter(p => p && (!pack.provinces[p] || pack.provinces[p].removed)); invalidProvinces.forEach(p => { const invalidCells = cells.i.filter(i => cells.province[i] === p); invalidCells.forEach(i => cells.province[i] = 0); - console.error("Data Integrity Check. Invalid province", p, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid province", p, "is assigned to cells", invalidCells); }); const invalidCultures = [...new Set(cells.culture)].filter(c => !pack.cultures[c] || pack.cultures[c].removed); invalidCultures.forEach(c => { const invalidCells = cells.i.filter(i => cells.culture[i] === c); invalidCells.forEach(i => cells.province[i] = 0); - console.error("Data Integrity Check. Invalid culture", c, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid culture", c, "is assigned to cells", invalidCells); }); const invalidReligions = [...new Set(cells.religion)].filter(r => !pack.religions[r] || pack.religions[r].removed); invalidReligions.forEach(r => { const invalidCells = cells.i.filter(i => cells.religion[i] === r); invalidCells.forEach(i => cells.religion[i] = 0); - console.error("Data Integrity Check. Invalid religion", c, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid religion", c, "is assigned to cells", invalidCells); }); const invalidFeatures = [...new Set(cells.f)].filter(f => f && !pack.features[f]); invalidFeatures.forEach(f => { const invalidCells = cells.i.filter(i => cells.f[i] === f); // No fix as for now - console.error("Data Integrity Check. Invalid feature", f, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid feature", f, "is assigned to cells", invalidCells); }); const invalidBurgs = [...new Set(cells.burg)].filter(b => b && (!pack.burgs[b] || pack.burgs[b].removed)); invalidBurgs.forEach(b => { const invalidCells = cells.i.filter(i => cells.burg[i] === b); invalidCells.forEach(i => cells.burg[i] = 0); - console.error("Data Integrity Check. Invalid burg", b, "is assigned to cells", invalidCells); + ERROR && console.error("Data Integrity Check. Invalid burg", b, "is assigned to cells", invalidCells); }); pack.burgs.forEach(b => { if (!b.i || b.removed) return; - if (b.port < 0) {console.error("Data Integrity Check. Burg", b.i, "has invalid port value", b.port); b.port = 0;} + if (b.port < 0) {ERROR && console.error("Data Integrity Check. Burg", b.i, "has invalid port value", b.port); b.port = 0;} if (b.cell < cells.i.length) return; - console.error("Data Integrity Check. Burg", b.i, "is linked to invalid cell", b.cell); + ERROR && console.error("Data Integrity Check. Burg", b.i, "is linked to invalid cell", b.cell); b.cell = findCell(b.x, b.y); cells.i.filter(i => cells.burg[i] === b.i).forEach(i => cells.burg[i] = 0); cells.burg[b.cell] = b.i; @@ -1065,13 +1065,13 @@ function parseLoadedData(data) { focusOn(); // based on searchParams focus on point, cell or burg invokeActiveZooming(); - console.warn(`TOTAL: ${rn((performance.now()-uploadMap.timeStart)/1000,2)}s`); + WARN && console.warn(`TOTAL: ${rn((performance.now()-uploadMap.timeStart)/1000,2)}s`); showStatistics(); - console.groupEnd("Loaded Map " + seed); + INFO && console.groupEnd("Loaded Map " + seed); tip("Map is successfully loaded", true, "success", 7000); } catch(error) { - console.error(error); + ERROR && console.error(error); clearMainTip(); alertMessage.innerHTML = `An error is occured on map loading. Select a different file to load, diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js index b129df88..0691fa3e 100644 --- a/modules/ui/burg-editor.js +++ b/modules/ui/burg-editor.js @@ -141,7 +141,7 @@ function editBurg(id) { const label = document.querySelector("#burgLabels [data-id='" + id + "']"); const icon = document.querySelector("#burgIcons [data-id='" + id + "']"); const anchor = document.querySelector("#anchors [data-id='" + id + "']"); - if (!label || !icon) {console.error("Cannot find label or icon elements"); return;} + if (!label || !icon) {ERROR && console.error("Cannot find label or icon elements"); return;} const labelG = document.querySelector("#burgLabels > #"+oldGroup); const iconG = document.querySelector("#burgIcons > #"+oldGroup); diff --git a/modules/ui/editors.js b/modules/ui/editors.js index fba98560..a67873ff 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -141,7 +141,7 @@ function moveBurgToGroup(id, g) { const label = document.querySelector("#burgLabels [data-id='" + id + "']"); const icon = document.querySelector("#burgIcons [data-id='" + id + "']"); const anchor = document.querySelector("#anchors [data-id='" + id + "']"); - if (!label || !icon) {console.error("Cannot find label or icon elements"); return;} + if (!label || !icon) {ERROR && console.error("Cannot find label or icon elements"); return;} document.querySelector("#burgLabels > #"+g).appendChild(label); document.querySelector("#burgIcons > #"+g).appendChild(icon); @@ -639,7 +639,7 @@ function selectIcon(initial, callback) { // Calls the refresh functionality on all editors currently open. function refreshAllEditors() { - console.time('refreshAllEditors'); + TIME && console.time('refreshAllEditors'); if (document.getElementById('culturesEditorRefresh').offsetParent) culturesEditorRefresh.click(); if (document.getElementById('biomesEditorRefresh').offsetParent) biomesEditorRefresh.click(); if (document.getElementById('diplomacyEditorRefresh').offsetParent) diplomacyEditorRefresh.click(); @@ -647,5 +647,5 @@ function refreshAllEditors() { if (document.getElementById('religionsEditorRefresh').offsetParent) religionsEditorRefresh.click(); if (document.getElementById('statesEditorRefresh').offsetParent) statesEditorRefresh.click(); if (document.getElementById('zonesEditorRefresh').offsetParent) zonesEditorRefresh.click(); - console.timeEnd('refreshAllEditors'); + TIME && console.timeEnd('refreshAllEditors'); } diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index f574f84e..66fba656 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -164,8 +164,8 @@ function editHeightmap() { } function regenerateErasedData() { - console.group("Edit Heightmap"); - console.time("regenerateErasedData"); + INFO && console.group("Edit Heightmap"); + TIME && console.time("regenerateErasedData"); const change = changeHeights.checked; markFeatures(); @@ -204,8 +204,8 @@ function editHeightmap() { Military.generate(); addMarkers(); addZones(); - console.timeEnd("regenerateErasedData"); - console.groupEnd("Edit Heightmap"); + TIME && console.timeEnd("regenerateErasedData"); + INFO && console.groupEnd("Edit Heightmap"); } function restoreKeptData() { @@ -216,8 +216,8 @@ function editHeightmap() { } function restoreRiskedData() { - console.group("Edit Heightmap"); - console.time("restoreRiskedData"); + INFO && console.group("Edit Heightmap"); + TIME && console.time("restoreRiskedData"); // assign pack data to grid cells const l = grid.cells.i.length; @@ -401,8 +401,8 @@ function editHeightmap() { .attr("points", d => getPackPolygon(d)).attr("id", d => base + d); }); - console.timeEnd("restoreRiskedData"); - console.groupEnd("Edit Heightmap"); + TIME && console.timeEnd("restoreRiskedData"); + INFO && console.groupEnd("Edit Heightmap"); } // trigger heightmap redraw and history update if at least 1 cell is changed @@ -954,7 +954,7 @@ function editHeightmap() { templateBody.innerHTML = ""; for (const s of steps) { const step = s.split(" "); - if (step.length !== 5) {console.error("Cannot parse step, wrong arguments count", s); continue;} + if (step.length !== 5) {ERROR && console.error("Cannot parse step, wrong arguments count", s); continue;} addStep(step[0], step[1], step[2], step[3], step[4]); } diff --git a/modules/ui/layers.js b/modules/ui/layers.js index b834c9d2..4ab03365 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -131,7 +131,7 @@ function toggleHeight(event) { } function drawHeightmap() { - console.time("drawHeightmap"); + TIME && console.time("drawHeightmap"); terrs.selectAll("*").remove(); const cells = pack.cells, vertices = pack.vertices, n = cells.i.length; const used = new Uint8Array(cells.i.length); @@ -188,7 +188,7 @@ function drawHeightmap() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } return chain; } @@ -199,7 +199,7 @@ function drawHeightmap() { return chain.filter((d, i) => i % n === 0); } - console.timeEnd("drawHeightmap"); + TIME && console.timeEnd("drawHeightmap"); } function getColorScheme() { @@ -228,7 +228,7 @@ function toggleTemp(event) { } function drawTemp() { - console.time("drawTemp"); + TIME && console.time("drawTemp"); temperature.selectAll("*").remove(); lineGen.curve(d3.curveBasisClosed); const scheme = d3.scaleSequential(d3.interpolateSpectral); @@ -311,12 +311,12 @@ function drawTemp() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } chain.push(start); return chain; } - console.timeEnd("drawTemp"); + TIME && console.timeEnd("drawTemp"); } function toggleBiomes(event) { @@ -370,7 +370,7 @@ function drawBiomes() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } return chain; } @@ -526,7 +526,7 @@ function drawIce() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } return chain; } @@ -547,7 +547,7 @@ function toggleCultures(event) { } function drawCultures() { - console.time("drawCultures"); + TIME && console.time("drawCultures"); cults.selectAll("path").remove(); const cells = pack.cells, vertices = pack.vertices, cultures = pack.cultures, n = cells.i.length; @@ -586,11 +586,11 @@ function drawCultures() { if (v[0] !== prev && c0 !== c1) current = v[0]; else if (v[1] !== prev && c1 !== c2) current = v[1]; else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1]) {ERROR && console.error("Next vertex is not found"); break;} } return chain; } - console.timeEnd("drawCultures"); + TIME && console.timeEnd("drawCultures"); } function toggleReligions(event) { @@ -607,7 +607,7 @@ function toggleReligions(event) { } function drawReligions() { - console.time("drawReligions"); + TIME && console.time("drawReligions"); relig.selectAll("path").remove(); const cells = pack.cells, vertices = pack.vertices, religions = pack.religions, features = pack.features, n = cells.i.length; @@ -657,12 +657,12 @@ function drawReligions() { if (v[0] !== prev && c0 !== c1) {current = v[0]; check(c0 ? c[0] : c[1]);} else if (v[1] !== prev && c1 !== c2) {current = v[1]; check(c1 ? c[1] : c[2]);} else if (v[2] !== prev && c0 !== c2) {current = v[2]; check(c2 ? c[2] : c[0]);} - if (current === chain[chain.length - 1][0]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1][0]) {ERROR && console.error("Next vertex is not found"); break;} } return chain; } - console.timeEnd("drawReligions"); + TIME && console.timeEnd("drawReligions"); } function toggleStates(event) { @@ -680,7 +680,7 @@ function toggleStates(event) { // draw states function drawStates() { - console.time("drawStates"); + TIME && console.time("drawStates"); regions.selectAll("path").remove(); const cells = pack.cells, vertices = pack.vertices, states = pack.states, n = cells.i.length; @@ -741,18 +741,18 @@ function drawStates() { if (v[0] !== prev && c0 !== c1) {current = v[0]; check(c0 ? c[0] : c[1]);} else if (v[1] !== prev && c1 !== c2) {current = v[1]; check(c1 ? c[1] : c[2]);} else if (v[2] !== prev && c0 !== c2) {current = v[2]; check(c2 ? c[2] : c[0]);} - if (current === chain[chain.length - 1][0]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length - 1][0]) {ERROR && console.error("Next vertex is not found"); break;} } chain.push([start, state, land]); // add starting vertex to sequence to close the path return chain; } invokeActiveZooming(); - console.timeEnd("drawStates"); + TIME && console.timeEnd("drawStates"); } // draw state and province borders function drawBorders() { - console.time("drawBorders"); + TIME && console.time("drawBorders"); borders.selectAll("path").remove(); const cells = pack.cells, vertices = pack.vertices, n = cells.i.length; @@ -807,7 +807,7 @@ function drawBorders() { // find starting vertex for (let i=0; i < 1000; i++) { - if (i === 999) console.error("Find starting vertex: limit is reached", current, f, t); + if (i === 999) ERROR && console.error("Find starting vertex: limit is reached", current, f, t); const p = chain[chain.length-2] || -1; // previous vertex const v = vertices.v[current], c = vertices.c[current]; @@ -825,7 +825,7 @@ function drawBorders() { chain = [current]; // vertices chain to form a path // find path for (let i=0; i < 1000; i++) { - if (i === 999) console.error("Find path: limit is reached", current, f, t); + if (i === 999) ERROR && console.error("Find path: limit is reached", current, f, t); const p = chain[chain.length-2] || -1; // previous vertex const v = vertices.v[current], c = vertices.c[current]; c.filter(c => array[c] === t).forEach(c => used[f][c] = t); @@ -845,7 +845,7 @@ function drawBorders() { return chain; } - console.timeEnd("drawBorders"); + TIME && console.timeEnd("drawBorders"); } function toggleBorders(event) { @@ -873,7 +873,7 @@ function toggleProvinces(event) { } function drawProvinces() { - console.time("drawProvinces"); + TIME && console.time("drawProvinces"); const labelsOn = provs.attr("data-labels") == 1; provs.selectAll("*").remove(); @@ -937,12 +937,12 @@ function drawProvinces() { if (v[0] !== prev && c0 !== c1) {current = v[0]; check(c0 ? c[0] : c[1]);} else if (v[1] !== prev && c1 !== c2) {current = v[1]; check(c1 ? c[1] : c[2]);} else if (v[2] !== prev && c0 !== c2) {current = v[2]; check(c2 ? c[2] : c[0]);} - if (current === chain[chain.length-1][0]) {console.error("Next vertex is not found"); break;} + if (current === chain[chain.length-1][0]) {ERROR && console.error("Next vertex is not found"); break;} } chain.push([start, province, land]); // add starting vertex to sequence to close the path return chain; } - console.timeEnd("drawProvinces"); + TIME && console.timeEnd("drawProvinces"); } function toggleGrid(event) { @@ -959,7 +959,7 @@ function toggleGrid(event) { } function drawGrid() { - console.time("drawGrid"); + TIME && console.time("drawGrid"); gridOverlay.selectAll("*").remove(); const type = styleGridType.value; const size = Math.max(+styleGridSize.value, 2); @@ -1003,7 +1003,7 @@ function drawGrid() { }); } - console.timeEnd("drawGrid"); + TIME && console.timeEnd("drawGrid"); } function toggleCoordinates(event) { diff --git a/modules/ui/style.js b/modules/ui/style.js index f715a884..e02393a7 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -653,7 +653,7 @@ function setBase64Texture(url) { }; function fetchTextureURL(url) { - console.log("Provided URL is", url); + INFO && console.log("Provided URL is", url); const img = new Image(); img.onload = function () { const canvas = document.getElementById("texturePreview"); diff --git a/modules/utils.js b/modules/utils.js index 31cd3093..352c7b59 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -471,14 +471,14 @@ function lim(v) { // get number from string in format "1-3" or "2" or "0.5" function getNumberInRange(r) { - if (typeof r !== "string") {console.error("The value should be a string", r); return 0;} + if (typeof r !== "string") {ERROR && console.error("The value should be a string", r); return 0;} if (!isNaN(+r)) return ~~r + +P(r - ~~r); const sign = r[0] === "-" ? -1 : 1; if (isNaN(+r[0])) r = r.slice(1); const range = r.includes("-") ? r.split("-") : null; - if (!range) {console.error("Cannot parse the number. Check the format", r); return 0;} + if (!range) {ERROR && console.error("Cannot parse the number. Check the format", r); return 0;} const count = rand(range[0] * sign, +range[1]); - if (isNaN(count) || count < 0) {console.error("Cannot parse number. Check the format", r); return 0;} + if (isNaN(count) || count < 0) {ERROR && console.error("Cannot parse number. Check the format", r); return 0;} return count; } @@ -603,7 +603,7 @@ void function() { const form = prompt.querySelector("#promptForm"); window.prompt = function(promptText = "Please provide an input", options = {default:1, step:.01, min:0, max:100}, callback) { - if (options.default === undefined) {console.error("Prompt: options object does not have default value defined"); return;} + if (options.default === undefined) {ERROR && console.error("Prompt: options object does not have default value defined"); return;} const input = prompt.querySelector("#promptInput"); prompt.querySelector("#promptText").innerHTML = promptText; const type = typeof(options.default) === "number" ? "number" : "text"; @@ -628,4 +628,4 @@ void function() { }() // indexedDB; ldb object -!function(){function e(t,o){return n?void(n.transaction("s").objectStore("s").get(t).onsuccess=function(e){var t=e.target.result&&e.target.result.v||null;o(t)}):void setTimeout(function(){e(t,o)},100)}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!t)return void console.error("indexedDB not supported");var n,o={k:"",v:""},r=t.open("d2",1);r.onsuccess=function(e){n=this.result},r.onerror=function(e){console.error("indexedDB request error"),console.log(e)},r.onupgradeneeded=function(e){n=null;var t=e.target.result.createObjectStore("s",{keyPath:"k"});t.transaction.oncomplete=function(e){n=e.target.db}},window.ldb={get:e,set:function(e,t){o.k=e,o.v=t,n.transaction("s","readwrite").objectStore("s").put(o)}}}(); \ No newline at end of file +!function(){function e(t,o){return n?void(n.transaction("s").objectStore("s").get(t).onsuccess=function(e){var t=e.target.result&&e.target.result.v||null;o(t)}):void setTimeout(function(){e(t,o)},100)}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!t)return void ERROR && console.error("indexedDB not supported");var n,o={k:"",v:""},r=t.open("d2",1);r.onsuccess=function(e){n=this.result},r.onerror=function(e){ERROR && console.error("indexedDB request error"),INFO && console.log(e)},r.onupgradeneeded=function(e){n=null;var t=e.target.result.createObjectStore("s",{keyPath:"k"});t.transaction.oncomplete=function(e){n=e.target.db}},window.ldb={get:e,set:function(e,t){o.k=e,o.v=t,n.transaction("s","readwrite").objectStore("s").put(o)}}}(); \ No newline at end of file From 14a46fd8430a98621fbb77b9d556640a43060934 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 26 Oct 2020 15:35:46 +0300 Subject: [PATCH 25/38] v1.4.46 --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 20586406..963a72d8 100644 --- a/index.html +++ b/index.html @@ -2744,7 +2744,7 @@ - + @@ -3162,7 +3162,7 @@ - + @@ -3537,7 +3537,7 @@ - + From 4920ccccb42d3192b54d9866fe56a2fd57a04205 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 8 Nov 2020 17:44:51 +0300 Subject: [PATCH 26/38] v1.4.47 --- modules/ui/options.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index 00797a84..b46b541d 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -71,9 +71,25 @@ document.getElementById("options").querySelector("div.tab").addEventListener("cl // show popup with a list of Patreon supportes (updated manually, to be replaced with API call) function showSupporters() { - const supporters = "Aaron Meyer, Ahmad Amerih, AstralJacks, aymeric, Billy Dean Goehring, Branndon Edwards, Chase Mayers, Curt Flood, cyninge, Dino Princip, E.M. White, es, Fondue, Fritjof Olsson, Gatsu, Johan Fröberg, Jonathan Moore, Joseph Miranda, Kate, KC138, Luke Nelson, Markus Finster, Massimo Vella, Mikey, Nathan Mitchell, Paavi1, Pat, Ryan Westcott, Sasquatch, Shawn Spencer, Sizz_TV, Timothée CALLET, UTG community, Vlad Tomash, Wil Sisney, William Merriott, Xariun, Gun Metal Games, Scott Marner, Spencer Sherman, Valerii Matskevych, Alloyed Clavicle, Stewart Walsh, Ruthlyn Mollett (Javan), Benjamin Mair-Pratt, Diagonath, Alexander Thomas, Ashley Wilson-Savoury, William Henry, Preston Brooks, JOSHUA QUALTIERI, Hilton Williams, Katharina Haase, Hisham Bedri, Ian arless, Karnat, Bird, Kevin, Jessica Thomas, Steve Hyatt, Logicspren, Alfred García, Jonathan Killstring, John Ackley, Invad3r233, Norbert Žigmund, Jennifer, PoliticsBuff, _gfx_, Maggie, Connor McMartin, Jared McDaris, BlastWind, Franc Casanova Ferrer, Dead & Devil, Michael Carmody, Valerie Elise, naikibens220, Jordon Phillips, William Pucs, The Dungeon Masters, Brady R Rathbun, J, Shadow, Matthew Tiffany, Huw Williams, Joseph Hamilton, FlippantFeline, Tamashi Toh, kms, Stephen Herron, MidnightMoon, Whakomatic x, Barished, Aaron bateson, Brice Moss, Diklyquill, PatronUser, Michael Greiner, Steven Bennett, Jacob Harrington, Miguel C., Reya C., Giant Monster Games, Noirbard, Brian Drennen, Ben Craigie, Alex Smolin, Endwords, Joshua E Goodwin, SirTobit , Allen S. Rout, Allen Bull Bear, Pippa Mitchell, R K, G0atfather, Ryan Lege, Caner Oleas Pekgönenç, Bradley Edwards, Tertiary , Austin Miller, Jesse Holmes, Jan Dvořák, Marten F, Erin D. Smale, Maxwell Hill, Drunken_Legends, rob bee, Jesse Holmes, YYako, Detocroix, Anoplexian, Hannah, Paul, Sandra Krohn, Lucid, Richard Keating, Allen Varney, Rick Falkvinge, Seth Fusion, Adam Butler, Gus, StroboWolf, Sadie Blackthorne, Zewen Senpai, Dell McKnight, Oneiris, Darinius Dragonclaw Studios, Christopher Whitney, Rhodes HvZ, Jeppe Skov Jensen, María Martín López, Martin Seeger, Annie Rishor, Aram Sabatés, MadNomadMedia, Eric Foley, Vito Martono, James H. Anthony, Kevin Cossutta, Thirty-OneR , ThatGuyGW , Dee Chiu, MontyBoosh , Achillain , Jaden , SashaTK, Steve Johnson"; - alertMessage.innerHTML = "
    " + supporters.split(", ").sort().map(n => `
  • ${n}
  • `).join("") + "
"; - $("#alert").dialog({resizable: false, title: "Patreon Supporters", width: "30vw", position: {my: "center", at: "center", of: "svg"}}); + const supporters = `Aaron Meyer,Ahmad Amerih,AstralJacks,aymeric,Billy Dean Goehring,Branndon Edwards,Chase Mayers,Curt Flood,cyninge,Dino Princip, + E.M. White,es,Fondue,Fritjof Olsson,Gatsu,Johan Fröberg,Jonathan Moore,Joseph Miranda,Kate,KC138,Luke Nelson,Markus Finster,Massimo Vella,Mikey, + Nathan Mitchell,Paavi1,Pat,Ryan Westcott,Sasquatch,Shawn Spencer,Sizz_TV,Timothée CALLET,UTG community,Vlad Tomash,Wil Sisney,William Merriott, + Xariun,Gun Metal Games,Scott Marner,Spencer Sherman,Valerii Matskevych,Alloyed Clavicle,Stewart Walsh,Ruthlyn Mollett (Javan),Benjamin Mair-Pratt, + Diagonath,Alexander Thomas,Ashley Wilson-Savoury,William Henry,Preston Brooks,JOSHUA QUALTIERI,Hilton Williams,Katharina Haase,Hisham Bedri,Ian arless, + Karnat,Bird,Kevin,Jessica Thomas,Steve Hyatt,Logicspren,Alfred García,Jonathan Killstring,John Ackley,Invad3r233,Norbert Žigmund,Jennifer, + PoliticsBuff,_gfx_,Maggie,Connor McMartin,Jared McDaris,BlastWind,Franc Casanova Ferrer,Dead & Devil,Michael Carmody,Valerie Elise,naikibens220, + Jordon Phillips,William Pucs,The Dungeon Masters,Brady R Rathbun,J,Shadow,Matthew Tiffany,Huw Williams,Joseph Hamilton,FlippantFeline,Tamashi Toh, + kms,Stephen Herron,MidnightMoon,Whakomatic x,Barished,Aaron bateson,Brice Moss,Diklyquill,PatronUser,Michael Greiner,Steven Bennett,Jacob Harrington, + Miguel C.,Reya C.,Giant Monster Games,Noirbard,Brian Drennen,Ben Craigie,Alex Smolin,Endwords,Joshua E Goodwin,SirTobit ,Allen S. Rout,Allen Bull Bear, + Pippa Mitchell,R K,G0atfather,Ryan Lege,Caner Oleas Pekgönenç,Bradley Edwards,Tertiary ,Austin Miller,Jesse Holmes,Jan Dvořák,Marten F,Erin D. Smale, + Maxwell Hill,Drunken_Legends,rob bee,Jesse Holmes,YYako,Detocroix,Anoplexian,Hannah,Paul,Sandra Krohn,Lucid,Richard Keating,Allen Varney,Rick Falkvinge, + Seth Fusion,Adam Butler,Gus,StroboWolf,Sadie Blackthorne,Zewen Senpai,Dell McKnight,Oneiris,Darinius Dragonclaw Studios,Christopher Whitney,Rhodes HvZ, + Jeppe Skov Jensen,María Martín López,Martin Seeger,Annie Rishor,Aram Sabatés,MadNomadMedia,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta, + Thirty-OneR ,ThatGuyGW ,Dee Chiu,MontyBoosh ,Achillain ,Jaden ,SashaTK,Steve Johnson,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta,Thirty-OneR, + ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,Andrew Rostaing,Daniel Gill`; + const array = supporters.replace(/(?:\r\n|\r|\n)/g, "").split(",").map(v => capitalize(v.trim())).sort(); + alertMessage.innerHTML = "
    " + array.map(n => `
  • ${n}
  • `).join("") + "
"; + $("#alert").dialog({resizable: false,title: "Patreon Supporters",width: "54vw",position: {my: "center",at: "center",of: "svg"}}); } // Option listeners From 554f51e463c41225a664b6eea430366d82d88449 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 5 Dec 2020 19:55:08 +0300 Subject: [PATCH 27/38] v1.4.48 --- .gitignore | 2 + Fantasy Map Generator.lnk | Bin 2304 -> 0 bytes README.md | 12 ++-- _config.yml | 1 - index.css | 7 +- index.html | 12 +--- modules/save-and-load.js | 142 +++++++++++++++++--------------------- modules/ui/general.js | 72 ++++++++++++++----- modules/ui/options.js | 6 +- modules/utils.js | 33 ++++----- 10 files changed, 154 insertions(+), 133 deletions(-) create mode 100644 .gitignore delete mode 100644 Fantasy Map Generator.lnk delete mode 100644 _config.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1104b06f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +run_php_server.bat +.vscode \ No newline at end of file diff --git a/Fantasy Map Generator.lnk b/Fantasy Map Generator.lnk deleted file mode 100644 index 1e1f20124b03a3e63bebe5c0f83cf3ac117927cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2304 zcmeZaU|?VrVPXJ*10aHd!R@vK2ZI6w0|S@cdY2%MYmB|xEWaMPBWQX9UietSR10#bP!~1=L z3=9mjJb12t{dtw~f4%dugZ9@L?FHjy>jbYciZFyQ7=jJ&4*1zAz~G));!&E!z+lI~ z$-u(!eqVmT%3_d=9s>h|WD3YFqF~hs!p8GFgF8beLkWWiLn%WN0|SE?LkZN(jREP) z1sL2M{X!gr>kJtfVxXor227s>k^`BV%+JEWz`%_#5X=hp31DzzNMy)kC}BusC}yZ+ z&}HytNMtBr&}DFENM*=lNM$HuNMtBs$Y&^GU|^77NMJBx0EOArfHk!W44!^2t`T*H zdLALZ3~q2+XHEjif^5~94Dw3?*e(Q79A?On$&km8!jQ^P!Jx;G!BE1G%aFssz#zrI z0H$R?G0DKd0HSrF8nYP~7(ijn%)r3#DN6K(07%@~DkiizwWv78qaem5Ke;qFHLs*N z1`@n6Zi#s%iN%$=zKI38?x}gHMTsT(MKPIqDXA5D86~+n3=BLBdJHjG-D1Sx%wWY3 z!w||)3=V^0h8PA9h608d1{a2WhGd3PhFoy?lrVr~kYgr>gb;P2i!C4@<}xHQq%)*~ zU7N{}%#hEJ$DqdmVS(a@nSo(J1Smuq7#I?((i0Pl3X-8*1_{egb&VNaE;IdBRjEJX z*w%V}aq|65uLPGWvGCbU=1UC1eSheO6ZyQ zdW|M1e}XKNhbB?%iGzUwlqvW@3LQX1Zj~!2M}q`;KztAblr%wXTLuOOP=aRw83~eb zX2@VDV#o)_ngW9dLkNQ}gAaoOMr?vKgVghZ7$9q41qO(}66%3vS;-o>3mhjAO?R1HwI4z9|l(jRVtTMgvyYi8-l~f button { - padding: 0; + padding: .3em; } #brushesButtons svg { @@ -1088,6 +1088,7 @@ i.resetButton:active { box-shadow: inset 1px 1px 0 0 #ccc; border-color: #a6a6da; background-color: #ecd8d8; + border-radius: 10%; } .ui-dialog input[type="range"] { @@ -1187,7 +1188,7 @@ div.slider .ui-slider-handle { #brushPower, #brushRadius { - width: 8em; + width: 12em; } #rescaleHigher, @@ -1261,7 +1262,7 @@ div.states { line-height: 1.5em; } -div.states:hover { +div.states:hover, div.states.hovered { border: 1px solid #c4c4c4; background-image: linear-gradient(to right, #dedede 100%, #f2f2f2 50%, #fcfcfc 0%); } diff --git a/index.html b/index.html index 963a72d8..e94c3839 100644 --- a/index.html +++ b/index.html @@ -7,8 +7,6 @@ - - @@ -34,13 +32,9 @@ #loading-text span:nth-child(3), #mapOverlay > span:nth-child(3) {animation-delay: 2s;} @keyframes blink {0% {opacity: 0;} 20% {opacity: 1;} 100% {opacity: .1;}} - - - - @@ -2649,8 +2643,8 @@ -
+
diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 7ee574a5..4cd42ad8 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -286,7 +286,6 @@ function getMapData() { TIME && console.timeEnd("createMapDataBlob"); resolve(blob); }); - } // Download .map file @@ -306,116 +305,103 @@ async function saveMap() { } function saveGeoJSON_Cells() { - let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; - const cells = pack.cells, v = pack.vertices; + const json = {type: "FeatureCollection", features: []}; + const cells = pack.cells; const getPopulation = i => {const [r, u] = getCellPopulation(i); return rn(r+u)}; + const getHeight = i => parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]])); cells.i.forEach(i => { - data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [["; - cells.v[i].forEach(n => { - let x = mapCoordinates.lonW + (v.p[n][0] / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (v.p[n][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - data += "["+x+","+y+"],"; - }); - // close the ring - let x = mapCoordinates.lonW + (v.p[cells.v[i][0]][0] / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (v.p[cells.v[i][0]][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - data += "["+x+","+y+"]"; - data += "]] },\n \"properties\": {\n"; + const coordinates = getCellPoints(cells.v[i]); + const height = getHeight(i); + const biome = cells.biome[i]; + const type = pack.features[cells.f[i]].type; + const population = getPopulation(i); + const state = cells.state[i]; + const province = cells.province[i]; + const culture = cells.culture[i]; + const religion = cells.religion[i]; + const neighbors = cells.c[i]; - const height = parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]])); - - data += " \"id\": \""+i+"\",\n"; - data += " \"height\": \""+height+"\",\n"; - data += " \"biome\": \""+cells.biome[i]+"\",\n"; - data += " \"type\": \""+pack.features[cells.f[i]].type+"\",\n"; - data += " \"population\": \""+getPopulation(i)+"\",\n"; - data += " \"state\": \""+cells.state[i]+"\",\n"; - data += " \"province\": \""+cells.province[i]+"\",\n"; - data += " \"culture\": \""+cells.culture[i]+"\",\n"; - data += " \"religion\": \""+cells.religion[i]+"\",\n"; - data += " \"neighbors\": ["+cells.c[i]+"]\n"; - data +=" }\n},\n"; + const properties = {id:i, height, biome, type, population, state, province, culture, religion, neighbors} + const feature = {type: "Feature", geometry: {type: "Polygon", coordinates}, properties}; + json.features.push(feature); }); - data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma - data += "]}"; - const name = getFileName("Cells") + ".geojson"; - downloadFile(data, name, "application/json"); + downloadFile(JSON.stringify(json), name, "application/json"); } -function saveGeoJSON_Roads() { - let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; +function saveGeoJSON_Routes() { + const json = {type: "FeatureCollection", features: []}; - routes._groups[0][0].childNodes.forEach(n => { - n.childNodes.forEach(r => { - data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"LineString\", \"coordinates\": "; - data += JSON.stringify(getRoadPoints(r)); - data += " },\n \"properties\": {\n"; - data += " \"id\": \""+r.id+"\",\n"; - data += " \"type\": \""+n.id+"\"\n"; - data +=" }\n},\n"; - }); + routes.selectAll("g > path").each(function() { + const coordinates = getRoutePoints(this); + const id = this.id; + const type = this.parentElement.id; + + const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, type}}; + json.features.push(feature); }); - data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma - data += "]}"; const name = getFileName("Routes") + ".geojson"; - downloadFile(data, name, "application/json"); + downloadFile(JSON.stringify(json), name, "application/json"); } function saveGeoJSON_Rivers() { - let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; + const json = {type: "FeatureCollection", features: []}; - rivers._groups[0][0].childNodes.forEach(n => { - data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"LineString\", \"coordinates\": "; - data += JSON.stringify(getRiverPoints(n)); - data += " },\n \"properties\": {\n"; - data += " \"id\": \""+n.id+"\",\n"; - data += " \"width\": \""+n.dataset.width+"\",\n"; - data += " \"increment\": \""+n.dataset.increment+"\"\n"; - data +=" }\n},\n"; + rivers.selectAll("path").each(function() { + const coordinates = getRiverPoints(this); + const id = this.id; + const width = +this.dataset.increment; + const increment = +this.dataset.increment; + const river = pack.rivers.find(r => r.i === +id.slice(5)); + const name = river ? river.name : ""; + const type = river ? river.type : ""; + const i = river ? river.i : ""; + const basin = river ? river.basin : ""; + + const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, i, basin, name, type, width, increment}}; + json.features.push(feature); }); - data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma - data += "]}"; const name = getFileName("Rivers") + ".geojson"; - downloadFile(data, name, "application/json"); + downloadFile(JSON.stringify(json), name, "application/json"); } function saveGeoJSON_Markers() { - let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; + const json = {type: "FeatureCollection", features: []}; - markers._groups[0][0].childNodes.forEach(n => { - let x = mapCoordinates.lonW + (n.dataset.x / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (n.dataset.y / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - - data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Point\", \"coordinates\": ["+x+", "+y+"]"; - data += " },\n \"properties\": {\n"; - data += " \"id\": \""+n.id+"\",\n"; - data += " \"type\": \""+n.dataset.id.substring(8)+"\"\n"; - data +=" }\n},\n"; + markers.selectAll("use").each(function() { + const coordinates = getQGIScoordinates(this.dataset.x, this.dataset.y); + const id = this.id; + const type = (this.dataset.id).substring(1); + const icon = document.getElementById(type).textContent; + const note = notes.length ? notes.find(note => note.id === this.id) : null; + const name = note ? note.name : ""; + const legend = note ? note.legend : ""; + const feature = {type: "Feature", geometry: {type: "Point", coordinates}, properties: {id, type, icon, name, legend}}; + json.features.push(feature); }); - data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma - data += "]}"; const name = getFileName("Markers") + ".geojson"; - downloadFile(data, name, "application/json"); + downloadFile(JSON.stringify(json), name, "application/json"); } -function getRoadPoints(node) { +function getCellPoints(vertices) { + const p = pack.vertices.p; + const points = vertices.map(n => getQGIScoordinates(p[n][0] / graphWidth, p[n][1] / graphHeight)); + return points.concat([points[0]]); +} + +function getRoutePoints(node) { let points = []; const l = node.getTotalLength(); const increment = l / Math.ceil(l / 2); for (let i=0; i <= l; i += increment) { const p = node.getPointAtLength(i); - - let x = mapCoordinates.lonW + (p.x / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (p.y / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - - points.push([x,y]); + points.push(getQGIScoordinates(p.x, p.y)); } return points; } @@ -427,9 +413,7 @@ function getRiverPoints(node) { for (let i=l, c=i; i >= 0; i -= increment, c += increment) { const p1 = node.getPointAtLength(i); const p2 = node.getPointAtLength(c); - - let x = mapCoordinates.lonW + (((p1.x+p2.x)/2) / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (((p1.y+p2.y)/2) / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise + const [x, y] = getQGIScoordinates((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); points.push([x,y]); } return points; diff --git a/modules/ui/general.js b/modules/ui/general.js index 7689b1b5..ca6ee9f7 100644 --- a/modules/ui/general.js +++ b/modules/ui/general.js @@ -27,7 +27,7 @@ function tip(tip = "Tip is undefined", main, type, time) { if (type === "success") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)"; if (main) tooltip.dataset.main = tip; // set main tip - if (time) setTimeout(tooltip.dataset.main = "", time); // clear main in some time + if (time) setTimeout(() => tooltip.dataset.main = "", time); // clear main in some time } function showMainTip() { @@ -49,7 +49,8 @@ function showDataTip(e) { tip(dataTip); } -function moved() { +const moved = debounce(mouseMove, 100); +function mouseMove() { const point = d3.mouse(this); const i = findCell(point[0], point[1]); // pack cell id if (i === undefined) return; @@ -89,11 +90,28 @@ function showMapTooltip(point, e, i, g) { const land = pack.cells.h[i] >= 20; // specific elements - if (group === "armies") {tip(e.target.parentNode.dataset.name + ". Click to edit"); return;} - if (group === "rivers") {tip(getRiverName(e.target.id) + "Click to edit"); return;} + if (group === "armies") { + tip(e.target.parentNode.dataset.name + ". Click to edit"); + return; + } + if (group === "rivers") { + const river = +e.target.id.slice(5); + const r = pack.rivers.find(r => r.i === river); + const name = r ? r.name + " " + r.type : ""; + tip(name + ". Click to edit"); + if (riversOverview.offsetParent) highlightEditorLine(riversOverview, river, 5000); + return; + } if (group === "routes") {tip("Click to edit the Route"); return;} if (group === "terrain") {tip("Click to edit the Relief Icon"); return;} - if (subgroup === "burgLabels" || subgroup === "burgIcons") {tip("Click to open Burg Editor"); return;} + if (subgroup === "burgLabels" || subgroup === "burgIcons") { + const burg = +path[path.length - 10].dataset.id; + const b = pack.burgs[burg]; + const population = si(b.population * populationRate.value * urbanization.value); + tip(`${b.name}. Population: ${population}. Click to edit`); + if (burgsOverview.offsetParent) highlightEditorLine(burgsOverview, burg, 5000); + return; + } if (group === "labels") {tip("Click to edit the Label"); return;} if (group === "markers") {tip("Click to edit the Marker"); return;} if (group === "ruler") { @@ -106,32 +124,54 @@ function showMapTooltip(point, e, i, g) { if (subgroup === "burgLabels") {tip("Click to edit the Burg"); return;} if (group === "lakes" && !land) {tip(`${capitalize(subgroup)} lake. Click to edit`); return;} if (group === "coastline") {tip("Click to edit the coastline"); return;} - if (group === "zones") {tip(path[path.length-8].dataset.description); return;} + if (group === "zones") { + const zone = path[path.length-8]; + tip(zone.dataset.description); + if (zonesEditor.offsetParent) highlightEditorLine(zonesEditor, zone.id, 5000); + return; + } if (group === "ice") {tip("Click to edit the Ice"); return;} // covering elements if (layerIsOn("togglePrec") && land) tip("Annual Precipitation: "+ getFriendlyPrecipitation(i)); else if (layerIsOn("togglePopulation")) tip(getPopulationTip(i)); else if (layerIsOn("toggleTemp")) tip("Temperature: " + convertTemperature(grid.cells.temp[g])); else - if (layerIsOn("toggleBiomes") && pack.cells.biome[i]) tip("Biome: " + biomesData.name[pack.cells.biome[i]]); else + if (layerIsOn("toggleBiomes") && pack.cells.biome[i]) { + const biome = pack.cells.biome[i] + tip("Biome: " + biomesData.name[biome]); + if (biomesEditor.offsetParent) highlightEditorLine(biomesEditor, biome); + } else if (layerIsOn("toggleReligions") && pack.cells.religion[i]) { - const religion = pack.religions[pack.cells.religion[i]]; - const type = religion.type === "Cult" || religion.type == "Heresy" ? religion.type : religion.type + " religion"; - tip(type + ": " + religion.name); + const religion = pack.cells.religion[i]; + const r = pack.religions[religion]; + const type = r.type === "Cult" || r.type == "Heresy" ? r.type : r.type + " religion"; + tip(type + ": " + r.name); + if (religionsEditor.offsetParent) highlightEditorLine(religionsEditor, religion); } else if (pack.cells.state[i] && (layerIsOn("toggleProvinces") || layerIsOn("toggleStates"))) { - const state = pack.states[pack.cells.state[i]].fullName; + const state = pack.cells.state[i]; + const stateName = pack.states[state].fullName; const province = pack.cells.province[i]; const prov = province ? pack.provinces[province].fullName + ", " : ""; - tip(prov + state); + tip(prov + stateName); + if (statesEditor.offsetParent) highlightEditorLine(statesEditor, state); + if (diplomacyEditor.offsetParent) highlightEditorLine(diplomacyEditor, state); + if (militaryOverview.offsetParent) highlightEditorLine(militaryOverview, state); + if (provincesEditor.offsetParent) highlightEditorLine(provincesEditor, province); + } else + if (layerIsOn("toggleCultures") && pack.cells.culture[i]) { + const culture = pack.cells.culture[i]; + tip("Culture: " + pack.cultures[culture].name); + if (culturesEditor.offsetParent) highlightEditorLine(culturesEditor, culture); } else - if (layerIsOn("toggleCultures") && pack.cells.culture[i]) tip("Culture: " + pack.cultures[pack.cells.culture[i]].name); else if (layerIsOn("toggleHeight")) tip("Height: " + getFriendlyHeight(point)); } -function getRiverName(id) { - const r = pack.rivers.find(r => r.i == id.slice(5)); - return r ? r.name + " " + r.type + ". " : ""; +function highlightEditorLine(editor, id, timeout = 15000) { + Array.from(editor.getElementsByClassName("states hovered")).forEach(el => el.classList.remove("hovered")); // clear all hovered + const hovered = Array.from(editor.querySelectorAll("div")).find(el => el.dataset.id == id); + if (hovered) hovered.classList.add("hovered"); // add hovered class + if (timeout) setTimeout(() => hovered.classList.remove("hovered"), timeout); } // get cell info on mouse move diff --git a/modules/ui/options.js b/modules/ui/options.js index b46b541d..4abe22ea 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -86,7 +86,9 @@ function showSupporters() { Seth Fusion,Adam Butler,Gus,StroboWolf,Sadie Blackthorne,Zewen Senpai,Dell McKnight,Oneiris,Darinius Dragonclaw Studios,Christopher Whitney,Rhodes HvZ, Jeppe Skov Jensen,María Martín López,Martin Seeger,Annie Rishor,Aram Sabatés,MadNomadMedia,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta, Thirty-OneR ,ThatGuyGW ,Dee Chiu,MontyBoosh ,Achillain ,Jaden ,SashaTK,Steve Johnson,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta,Thirty-OneR, - ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,Andrew Rostaing,Daniel Gill`; + ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,Andrew Rostaing,Daniel Gill, + Char, Jack, Barna Csíkos, Ian Rousseau, Nicholas Grabstas, Tom Van Orden jr, Bryan Brake, Akylos, Riley Seaman`; + const array = supporters.replace(/(?:\r\n|\r|\n)/g, "").split(",").map(v => capitalize(v.trim())).sort(); alertMessage.innerHTML = "
    " + array.map(n => `
  • ${n}
  • `).join("") + "
"; $("#alert").dialog({resizable: false,title: "Patreon Supporters",width: "54vw",position: {my: "center",at: "center",of: "svg"}}); @@ -481,7 +483,7 @@ function saveGeoJSON() { $("#alert").dialog({title: "GIS data export", resizable: false, width: "35em", position: {my: "center", at: "center", of: "svg"}, buttons: { Cells: saveGeoJSON_Cells, - Routes: saveGeoJSON_Roads, + Routes: saveGeoJSON_Routes, Rivers: saveGeoJSON_Rivers, Markers: saveGeoJSON_Markers, Close: function() {$(this).dialog("close");} diff --git a/modules/utils.js b/modules/utils.js index 352c7b59..005d0738 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -516,26 +516,15 @@ function getNextId(core, i = 1) { return core + i; } -// from https://davidwalsh.name/javascript-debounce-function -function debounce(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - } - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - } -} +function debounce(f, ms) { + let isCooldown = false; -// pause/block JS execution for a while -function sleep(delay) { - const start = new Date().getTime(); - while (new Date().getTime() < start + delay); + return function() { + if (isCooldown) return; + f.apply(this, arguments); + isCooldown = true; + setTimeout(() => isCooldown = false, ms); + }; } // parse error to get the readable string in Chrome and Firefox @@ -597,6 +586,12 @@ function generateDate(from = 100, to = 1000) { return new Date(rand(from, to),rand(12),rand(31)).toLocaleDateString("en", {year:'numeric', month:'long', day:'numeric'}); } +function getQGIScoordinates(x, y) { + const cx = mapCoordinates.lonW + (x / graphWidth) * mapCoordinates.lonT; + const cy = mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise + return [cx, cy]; +} + // prompt replacer (prompt does not work in Electron) void function() { const prompt = document.getElementById("prompt"); From d3431afb2495c1f9778d685b15aa2cf7fb5e9603 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 13 Dec 2020 21:02:32 +0300 Subject: [PATCH 28/38] v1.4.49 --- LICENSE | 4 ++-- modules/save-and-load.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index 19e4e777..24402ab6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright 2018-2019 Max Ganiev (Azgaar), azgaar.fmg@yandex.by +Copyright 2018-2020 Max Ganiev (Azgaar), azgaar.fmg@yandex.by Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -12,7 +12,7 @@ furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -You can produce, without restrictions, any derivative works from the original +You can produce, without restrictions, any derivative works from the original software and even reap commercial benefits from the sale of the secondary product. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 4cd42ad8..da44cf26 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -311,7 +311,7 @@ function saveGeoJSON_Cells() { const getHeight = i => parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]])); cells.i.forEach(i => { - const coordinates = getCellPoints(cells.v[i]); + const coordinates = getCellCoordinates(cells.v[i]); const height = getHeight(i); const biome = cells.biome[i]; const type = pack.features[cells.f[i]].type; @@ -389,10 +389,10 @@ function saveGeoJSON_Markers() { downloadFile(JSON.stringify(json), name, "application/json"); } -function getCellPoints(vertices) { +function getCellCoordinates(vertices) { const p = pack.vertices.p; - const points = vertices.map(n => getQGIScoordinates(p[n][0] / graphWidth, p[n][1] / graphHeight)); - return points.concat([points[0]]); + const coordinates = vertices.map(n => getQGIScoordinates(p[n][0], p[n][1])); + return coordinates.concat([coordinates[0]]); } function getRoutePoints(node) { From f1957ea9bc2acf8410a29538e1e6c32a706c40b1 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 14 Dec 2020 19:44:43 +0300 Subject: [PATCH 29/38] v1.4.5 --- modules/save-and-load.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/save-and-load.js b/modules/save-and-load.js index da44cf26..86d7e6db 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -392,7 +392,7 @@ function saveGeoJSON_Markers() { function getCellCoordinates(vertices) { const p = pack.vertices.p; const coordinates = vertices.map(n => getQGIScoordinates(p[n][0], p[n][1])); - return coordinates.concat([coordinates[0]]); + return [coordinates.concat([coordinates[0]])]; } function getRoutePoints(node) { From 9870fcc3391096a50a103113888c578336ec5bbf Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 17 Dec 2020 23:20:50 +0300 Subject: [PATCH 30/38] v1.4.6 --- modules/ui/burg-editor.js | 2 +- modules/ui/provinces-editor.js | 2 +- modules/ui/states-editor.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js index 0691fa3e..9a3af95c 100644 --- a/modules/ui/burg-editor.js +++ b/modules/ui/burg-editor.js @@ -328,7 +328,7 @@ function editBurg(id) { function openInIAHG(event) { const id = elSelected.attr("data-id"), burg = pack.burgs[id], defSeed = `${seed}-b${id}`; - const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (burg.IAHG || defSeed)); + const openIAHG = () => openURL("https://ironarachne.com/#/heraldry/" + (burg.IAHG || defSeed)); if (isCtrlClick(event)) { prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and burg id (${defSeed})`, diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index 3d64fafc..c794386a 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -194,7 +194,7 @@ function editProvinces() { function provinceOpenCOA(event, p) { const defSeed = `${seed}-p${p}`; - const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.provinces[p].IAHG || defSeed)); + const openIAHG = () => openURL("https://ironarachne.com/#/heraldry/" + (pack.provinces[p].IAHG || defSeed)); if (isCtrlClick(event)) { prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and province id (${defSeed})`, diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index f4c123a7..43e00888 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -315,7 +315,7 @@ function editStates() { function stateOpenCOA(event, state) { const defSeed = `${seed}-s${state}`; - const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.states[state].IAHG || defSeed)); + const openIAHG = () => openURL("https://ironarachne.com/#/heraldry/" + (pack.states[state].IAHG || defSeed)); if (isCtrlClick(event)) { prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and state id (${defSeed})`, From 576a6996cac76f519fbbd17ed634262c6aff17b4 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 30 Dec 2020 12:09:40 +0300 Subject: [PATCH 31/38] v1.4.61 --- modules/ui/layers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui/layers.js b/modules/ui/layers.js index 4ab03365..19c05a6f 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -165,7 +165,7 @@ function drawHeightmap() { paths[h] += round(lineGen(points)); } - terrs.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("fill", scheme(.8)); // draw base layer + terrs.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight).attr("fill", scheme(.8)); // draw base layer for (const i of d3.range(20, 101)) { if (paths[i].length < 10) continue; const color = getColor(i, scheme); From d9d5d182fd7fb0e9f38738c65c23acc33084fb6f Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 30 Dec 2020 12:39:21 +0300 Subject: [PATCH 32/38] v1.4.62 --- index.html | 6 +++--- modules/ui/markers-editor.js | 11 ++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index e94c3839..b4da0dd6 100644 --- a/index.html +++ b/index.html @@ -2414,11 +2414,11 @@ -
+
Urbanization rate:
diff --git a/modules/ui/layers.js b/modules/ui/layers.js index 19c05a6f..f91d7b25 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -257,8 +257,8 @@ function drawTemp() { addLabel(points, t); } - // min temp isoline covers all map - temperature.append("path").attr("d", `M0,0 h${svgWidth} v${svgHeight} h${-svgWidth} Z`).attr("fill", scheme(1 - (min - tMin) / delta)).attr("stroke", "none"); + // min temp isoline covers all graph + temperature.append("path").attr("d", `M0,0 h${graphWidth} v${graphHeight} h${-graphWidth} Z`).attr("fill", scheme(1 - (min - tMin) / delta)).attr("stroke", "none"); for (const t of isolines) { const path = chains.filter(c => c[0] === t).map(c => round(lineGen(c[1]))).join(""); @@ -1064,9 +1064,6 @@ function toggleCompass(event) { $('#compass').fadeIn(); if (!compass.selectAll("*").size()) { compass.append("use").attr("xlink:href","#rose"); - // prolongate rose lines - svg.select("g#rose > g#sL > line#sL1").attr("y1", -19000).attr("y2", 19000); - svg.select("g#rose > g#sL > line#sL2").attr("x1", -19000).attr("x2", 19000); shiftCompass(); } if (event && isCtrlClick(event)) editStyle("compass"); From 89b217408413a0609f2f99f6bd92ed1ec24fd197 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 30 Dec 2020 14:06:00 +0300 Subject: [PATCH 34/38] v1.4.64 --- modules/ui/layers.js | 2 +- modules/ui/options.js | 2 ++ modules/ui/style.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/ui/layers.js b/modules/ui/layers.js index f91d7b25..6f66e108 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -962,7 +962,7 @@ function drawGrid() { TIME && console.time("drawGrid"); gridOverlay.selectAll("*").remove(); const type = styleGridType.value; - const size = Math.max(+styleGridSize.value, 2); + const size = Math.max(+styleGridSize.value || +gridOverlay.attr("size"), 2); if (type === "pointyHex" || type === "flatHex") { const points = getHexGridPoints(size, type); const hex = "m" + getHex(size, type).slice(0, 4).join("l"); diff --git a/modules/ui/options.js b/modules/ui/options.js index 4abe22ea..74022100 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -158,6 +158,8 @@ function changeMapSize() { landmass.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); + fogging.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); + defs.select("mask#fog > rect").attr("width", maxWidth).attr("height", maxHeight); fitScaleBar(); if (window.fitLegendBox) fitLegendBox(); diff --git a/modules/ui/style.js b/modules/ui/style.js index e02393a7..db3b1db8 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -721,7 +721,7 @@ function applyDefaultStyle() { provinceBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .2).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt").attr("filter", null); cells.attr("opacity", null).attr("stroke", "#808080").attr("stroke-width", .1).attr("filter", null).attr("mask", null); - gridOverlay.attr("opacity", .8).attr("type", "pointyHex").attr("size", 10).attr("stroke", "#808080").attr("stroke-width", .5).attr("stroke-dasharray", null).attr("transform", null).attr("filter", null).attr("mask", null); + gridOverlay.attr("opacity", .8).attr("type", "pointyHex").attr("size", 20).attr("stroke", "#808080").attr("stroke-width", .5).attr("stroke-dasharray", null).attr("transform", null).attr("filter", null).attr("mask", null); coordinates.attr("opacity", 1).attr("data-size", 12).attr("font-size", 12).attr("stroke", "#d4d4d4").attr("stroke-width", 1).attr("stroke-dasharray", 5).attr("filter", null).attr("mask", null); compass.attr("opacity", .8).attr("transform", null).attr("filter", null).attr("mask", "url(#water)").attr("shape-rendering", "optimizespeed"); if (!d3.select("#initial").size()) d3.select("#rose").attr("transform", "translate(80 80) scale(.25)"); From aae3c5d17ded53633c4aa300bd8a59bf6155459c Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 30 Dec 2020 15:58:27 +0300 Subject: [PATCH 35/38] v1.4.65 --- modules/ui/options.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ui/options.js b/modules/ui/options.js index 74022100..ccf5fc68 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -160,6 +160,7 @@ function changeMapSize() { oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); fogging.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); defs.select("mask#fog > rect").attr("width", maxWidth).attr("height", maxHeight); + texture.select("image").attr("width", maxWidth).attr("height", maxHeight); fitScaleBar(); if (window.fitLegendBox) fitLegendBox(); From 40e59305713dc33fbba84df296b9e4aedb4e6a50 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 3 Jan 2021 13:53:02 +0300 Subject: [PATCH 36/38] v1.4.66 --- modules/ui/options.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ui/options.js b/modules/ui/options.js index ccf5fc68..24434e2d 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -87,7 +87,8 @@ function showSupporters() { Jeppe Skov Jensen,María Martín López,Martin Seeger,Annie Rishor,Aram Sabatés,MadNomadMedia,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta, Thirty-OneR ,ThatGuyGW ,Dee Chiu,MontyBoosh ,Achillain ,Jaden ,SashaTK,Steve Johnson,Eric Foley,Vito Martono,James H. Anthony,Kevin Cossutta,Thirty-OneR, ThatGuyGW,Dee Chiu,MontyBoosh,Achillain,Jaden,SashaTK,Steve Johnson,Pierrick Bertrand,Jared Kennedy,Dylan Devenny,Kyle Robertson,Andrew Rostaing,Daniel Gill, - Char, Jack, Barna Csíkos, Ian Rousseau, Nicholas Grabstas, Tom Van Orden jr, Bryan Brake, Akylos, Riley Seaman`; + Char, Jack, Barna Csíkos, Ian Rousseau, Nicholas Grabstas, Tom Van Orden jr, Bryan Brake, Akylos, Riley Seaman, + MaxOliver, Evan-DiLeo, Alex Debus, Joshua Vaught, Kyle S, Eric Moore, Dean Dunakin, Uniquenameosaurus, WarWizardGames`; const array = supporters.replace(/(?:\r\n|\r|\n)/g, "").split(",").map(v => capitalize(v.trim())).sort(); alertMessage.innerHTML = "
    " + array.map(n => `
  • ${n}
  • `).join("") + "
"; From ed33864e07c1c1c36a21abb3fc91bb184b7d246b Mon Sep 17 00:00:00 2001 From: Alexander James Date: Thu, 4 Feb 2021 06:33:08 -0700 Subject: [PATCH 37/38] Elevated Lakes (#554) Fix #465 (river/lake) by @CanisArtorus * Give lake features a height attribute * Outflow changes * Outlets afterwards * Fix river identities * Pathfind big river across small-basin lakes. * Scrap pathing, too ambitious * Delete extraneous (de-)elevateLakes * Code cleanup * Attempt drawing improvements * Make outflows a river again. * Edge Cases. Explore drawing width. * Pretty up. River initial width. --- main.js | 18 ---- modules/river-generator.js | 163 +++++++++++++++++++++++-------- modules/ui/heightmap-editor.js | 3 - modules/ui/tools.js | 5 - modules/ui/world-configurator.js | 1 - 5 files changed, 120 insertions(+), 70 deletions(-) diff --git a/main.js b/main.js index 3ab242d7..3add6200 100644 --- a/main.js +++ b/main.js @@ -530,7 +530,6 @@ function generate() { reGraph(); drawCoastline(); - elevateLakes(); Rivers.generate(); defineBiomes(); @@ -1122,22 +1121,6 @@ function reMarkFeatures() { TIME && console.timeEnd("reMarkFeatures"); } -// temporary elevate some lakes to resolve depressions and flux the water to form an open (exorheic) lake -function elevateLakes() { - if (templateInput.value === "Atoll") return; // no need for Atolls - TIME && console.time('elevateLakes'); - const cells = pack.cells, features = pack.features; - const maxCells = cells.i.length / 100; // size limit; let big lakes be closed (endorheic) - cells.i.forEach(i => { - if (cells.h[i] >= 20) return; - if (features[cells.f[i]].group !== "freshwater" || features[cells.f[i]].cells > maxCells) return; - cells.h[i] = 20; - //debug.append("circle").attr("cx", cells.p[i][0]).attr("cy", cells.p[i][1]).attr("r", .5).attr("fill", "blue"); - }); - - TIME && console.timeEnd('elevateLakes'); -} - // assign biome id for each cell function defineBiomes() { TIME && console.time("defineBiomes"); @@ -1145,7 +1128,6 @@ function defineBiomes() { cells.biome = new Uint8Array(cells.i.length); // biomes array for (const i of cells.i) { - if (f[cells.f[i]].group === "freshwater") cells.h[i] = 19; // de-elevate lakes; here to save some resources const t = temp[cells.g[i]]; // cell temperature const h = cells.h[i]; // cell height const m = h < 20 ? 0 : calculateMoisture(i); // cell moisture diff --git a/modules/river-generator.js b/modules/river-generator.js index 078392e1..54fc1b3a 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -25,7 +25,7 @@ .map((h, i) => h < 20 || cells.t[i] < 1 ? h : h + d3.mean(cells.c[i].map(c => cells.t[c])) / 10000); resolveDepressions(h); - features.forEach(f => {delete f.river; delete f.flux;}); + features.forEach(f => {delete f.river; delete f.flux; delete f.inlets}); const riversData = []; // rivers data cells.fl = new Uint16Array(cells.i.length); // water flux array @@ -35,10 +35,95 @@ void function drainWater() { const land = cells.i.filter(i => h[i] >= 20).sort((a,b) => h[b] - h[a]); + const outlets = new Uint32Array(features.length); + // enumerate lake outlet positions + features.filter(f => f.type === "lake" && (f.group === "freshwater" || f.group === "frozen")).forEach(l => { + let outlet = 0; + if (l.shoreline) { + outlet = l.shoreline[d3.scan(l.shoreline, (a,b) => h[a] - h[b])]; + } else { // in case it got missed or deleted + WARN && console.warn('Re-scanning shoreline of a lake'); + const shallows = cells.i.filter(j => cells.t[j] === -1 && cells.f[j] === l.i); + let shoreline = []; + shallows.map(w => cells.c[w]).forEach(cList => cList.forEach(s => shoreline.push(s))); + outlet = shoreline[d3.scan(shoreline, (a,b) => h[a] - h[b])]; + } + outlets[l.i] = outlet; + delete l.shoreline // cleanup temp data once used + }); + + const flowDown = function(min, mFlux, iFlux, ri, i = 0){ + if (cells.r[min]) { // downhill cell already has river assigned + if (mFlux < iFlux) { + cells.conf[min] = cells.fl[min]; // mark confluence + if (h[min] >= 20) riversData.find(r => r.river === cells.r[min]).parent = ri; // min river is a tributary of current river + cells.r[min] = ri; // re-assign river if downhill part has less flux + } else { + cells.conf[min] += iFlux; // mark confluence + if (h[min] >= 20) riversData.find(r => r.river === ri).parent = cells.r[min]; // current river is a tributary of min river + } + } else cells.r[min] = ri; // assign the river to the downhill cell + + if (h[min] < 20) { + // pour water to the sea haven + const oh = i ? cells.haven[i] : min; + riversData.push({river: ri, cell: oh, x: p[min][0], y: p[min][1]}); + const mf = features[cells.f[min]]; // feature of min cell + if (mf.type === "lake") { + if (!mf.river || iFlux > mf.flux) { + mf.river = ri; // pour water to temporaly elevated lake + mf.flux = iFlux; // entering flux + } + mf.totalFlux += iFlux; + if (mf.inlets) { + mf.inlets.push(ri); + } else { + mf.inlets = [ri]; + } + } + } else { + cells.fl[min] += iFlux; // propagate flux + riversData.push({river: ri, cell: min, x: p[min][0], y: p[min][1]}); // add next River segment + } + } + land.forEach(function(i) { cells.fl[i] += grid.cells.prec[cells.g[i]]; // flux from precipitation const x = p[i][0], y = p[i][1]; + // lake outlets draw from lake + let n = -1, out2 = 0; + while (outlets.includes(i, n+1)) { + n = outlets.indexOf(i, n+1); + const l = features[n]; + if ( ! l ) {continue;} + const j = cells.haven[i]; + // allow chain lakes to retain identity + if(cells.r[j] !== l.river) { + let touch = false; + for (const c of cells.c[j]){ + if (cells.r[c] === l.river) { + touch = true; + break; + } + } + if (touch) { + cells.r[j] = l.river; + riversData.push({river: l.river, cell: j, x: p[j][0], y: p[j][1]}); + } else { + cells.r[j] = riverNext; + riversData.push({river: riverNext, cell: j, x: p[j][0], y: p[j][1]}); + riverNext++; + } + } + cells.fl[j] = l.totalFlux; // signpost river size + flowDown(i, cells.fl[i], l.totalFlux, cells.r[j]); + // prevent dropping imediately back into the lake + out2 = cells.c[i].filter(c => (h[c] >= 20 || cells.f[c] !== cells.f[j])).sort((a,b) => h[a] - h[b])[0]; // downhill cell not in the source lake + // assign all to outlet basin + if (l.inlets) l.inlets.forEach(fork => riversData.find(r => r.river === fork).parent = cells.r[j]); + } + // near-border cell: pour out of the screen if (cells.b[i]) { if (cells.r[i]) { @@ -53,14 +138,7 @@ return; } - //const min = cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell - let min = cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell - - // allow only one river can flow through a lake - const cf = features[cells.f[i]]; // current cell feature - if (cf.river && cf.river !== cells.r[i]) { - cells.fl[i] = 0; - } + const min = out2 ? out2 : cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell if (cells.fl[i] < 30) { if (h[min] >= 20) cells.fl[min] += cells.fl[i]; @@ -74,32 +152,7 @@ riverNext++; } - if (cells.r[min]) { // downhill cell already has river assigned - if (cells.fl[min] < cells.fl[i]) { - cells.conf[min] = cells.fl[min]; // mark confluence - if (h[min] >= 20) riversData.find(r => r.river === cells.r[min]).parent = cells.r[i]; // min river is a tributary of current river - cells.r[min] = cells.r[i]; // re-assign river if downhill part has less flux - } else { - cells.conf[min] += cells.fl[i]; // mark confluence - if (h[min] >= 20) riversData.find(r => r.river === cells.r[i]).parent = cells.r[min]; // current river is a tributary of min river - } - } else cells.r[min] = cells.r[i]; // assign the river to the downhill cell - - const nx = p[min][0], ny = p[min][1]; - if (h[min] < 20) { - // pour water to the sea haven - riversData.push({river: cells.r[i], cell: cells.haven[i], x: nx, y: ny}); - } else { - const mf = features[cells.f[min]]; // feature of min cell - if (mf.type === "lake") { - if (!mf.river || cells.fl[i] > mf.flux) { - mf.river = cells.r[i]; // pour water to temporaly elevated lake - mf.flux = cells.fl[i]; // entering flux - } - } - cells.fl[min] += cells.fl[i]; // propagate flux - riversData.push({river: cells.r[i], cell: min, x: nx, y: ny}); // add next River segment - } + flowDown(min, cells.fl[min], cells.fl[i], cells.r[i], i); }); }() @@ -112,12 +165,12 @@ const riverSegments = riversData.filter(d => d.river === r); if (riverSegments.length > 2) { - const riverEnhanced = addMeandring(riverSegments); - const width = rn(.8 + Math.random() * .4, 1); // river width modifier - const increment = rn(.8 + Math.random() * .6, 1); // river bed widening modifier - const [path, length] = getPath(riverEnhanced, width, increment); - riverPaths.push([r, path, width, increment]); const source = riverSegments[0], mouth = riverSegments[riverSegments.length-2]; + const riverEnhanced = addMeandring(riverSegments); + let width = rn(.8 + Math.random() * .4, 1); // river width modifier [.2, 10] + let increment = rn(.8 + Math.random() * .6, 1); // river bed widening modifier [.01, 3] + const [path, length] = getPath(riverEnhanced, width, increment, cells.h[source.cell] >= 20 ? .1 : .6); + riverPaths.push([r, path, width, increment]); const parent = source.parent || 0; pack.rivers.push({i:r, parent, length, source:source.cell, mouth:mouth.cell}); } else { @@ -143,13 +196,37 @@ const resolveDepressions = function(h) { const cells = pack.cells; const land = cells.i.filter(i => h[i] >= 20 && h[i] < 100 && !cells.b[i]); // exclude near-border cells + const lakes = pack.features.filter(f => f.type === "lake" && (f.group === "freshwater" || f.group === "frozen")); // to keep lakes flat + lakes.forEach(l => { + l.shoreline = []; + l.height = 21; + l.totalFlux = grid.cells.prec[cells.g[l.firstCell]]; + }); + for (let i of land.filter(i => cells.t[i] === 1)) { // select shoreline cells + cells.c[i].map(c => pack.features[cells.f[c]]).forEach(cf => { + if (lakes.includes(cf) && !cf.shoreline.includes(i)) { + cf.shoreline.push(i); + } + }) + } land.sort((a,b) => h[b] - h[a]); // highest cells go first let depressed = false; for (let l = 0, depression = Infinity; depression && l < 100; l++) { depression = 0; + for (const l of lakes) { + const minHeight = d3.min(l.shoreline.map(s => h[s])); + if (minHeight === 100) continue; // already max height + if (l.height <= minHeight) { + l.height = Math.min(minHeight + 1, 100); + depression++; + depressed = true; + } + } for (const i of land) { - const minHeight = d3.min(cells.c[i].map(c => h[c])); + const minHeight = d3.min(cells.c[i].map(c => cells.t[c] > 0 ? h[c] : + pack.features[cells.f[c]].height || h[c] // NB undefined is falsy (a || b is short for a ? a : b) + )); if (minHeight === 100) continue; // already max height if (h[i] <= minHeight) { h[i] = Math.min(minHeight + 1, 100); @@ -200,8 +277,8 @@ return riverEnhanced; } - const getPath = function(points, width = 1, increment = 1) { - let offset, extraOffset = .1; // starting river width (to make river source visible) + const getPath = function(points, width = 1, increment = 1, starting = .1) { + let offset, extraOffset = starting; // starting river width (to make river source visible) const riverLength = points.reduce((s, v, i, p) => s + (i ? Math.hypot(v[0] - p[i-1][0], v[1] - p[i-1][1]) : 0), 0); // summ of segments length const widening = rn((1000 + (riverLength * 30)) * increment); const riverPointsLeft = [], riverPointsRight = []; // store points on both sides to build a valid polygon diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 66fba656..b2f7712a 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -176,7 +176,6 @@ function editHeightmap() { reGraph(); drawCoastline(); - elevateLakes(); Rivers.generate(change); if (!change) { @@ -289,7 +288,6 @@ function editHeightmap() { drawCoastline(); if (changeHeights.checked) { - elevateLakes(); Rivers.generate(changeHeights.checked); } @@ -314,7 +312,6 @@ function editHeightmap() { for (const i of pack.cells.i) { const g = pack.cells.g[i]; - if (pack.features[pack.cells.f[i]].group === "freshwater") pack.cells.h[i] = 19; // de-elevate lakes const land = pack.cells.h[i] >= 20; // check biome diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 066eda0b..15988bf8 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -72,12 +72,7 @@ function processFeatureRegeneration(event, button) { } function regenerateRivers() { - elevateLakes(); Rivers.generate(); - for (const i of pack.cells.i) { - const f = pack.features[pack.cells.f[i]]; // feature - if (f.group === "freshwater") pack.cells.h[i] = 19; // de-elevate lakes - } Rivers.specify(); if (!layerIsOn("toggleRivers")) toggleRivers(); } diff --git a/modules/ui/world-configurator.js b/modules/ui/world-configurator.js index ffcef39f..fc3f93b6 100644 --- a/modules/ui/world-configurator.js +++ b/modules/ui/world-configurator.js @@ -45,7 +45,6 @@ function editWorld() { updateGlobePosition(); calculateTemperatures(); generatePrecipitation(); - elevateLakes(); const heights = new Uint8Array(pack.cells.h); Rivers.generate(); Rivers.specify(); From 7b911511799abf300882b98e9011864d6b620913 Mon Sep 17 00:00:00 2001 From: Gabriel Britain Date: Thu, 4 Feb 2021 08:51:29 -0500 Subject: [PATCH 38/38] Modernize voronoi (#557) Voronoi.js modernization by @SaltyQuetzals * Changed Voronoi generator to be more class-based, added mediocre documentation. * Added spaces to JSDoc links so text doesn't bleed into URL * Found delaunator docs, very helpful in writing function documentation. --- main.js | 4 +- modules/burgs-and-states.js | 2 +- modules/voronoi.js | 186 +++++++++++++++++++++++------------- 3 files changed, 123 insertions(+), 69 deletions(-) diff --git a/main.js b/main.js index 3add6200..bf2adc37 100644 --- a/main.js +++ b/main.js @@ -12,7 +12,7 @@ document.title += " v" + version; // Switches to disable/enable logging features const INFO = 0; -const TIME = 0; +const TIME = 1; const WARN = 1; const ERROR = 1; @@ -610,7 +610,7 @@ function calculateVoronoi(graph, points) { TIME && console.timeEnd("calculateDelaunay"); TIME && console.time("calculateVoronoi"); - const voronoi = Voronoi(delaunay, allPoints, n); + const voronoi = new Voronoi(delaunay, allPoints, n); graph.cells = voronoi.cells; graph.cells.i = n < 65535 ? Uint16Array.from(d3.range(n)) : Uint32Array.from(d3.range(n)); // array of indexes graph.vertices = voronoi.vertices; diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index bbb48e4f..924280e3 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -394,7 +394,7 @@ const hull = getHull(start, s.i, s.cells / 10); const points = [...hull].map(v => pack.vertices.p[v]); const delaunay = Delaunator.from(points); - const voronoi = Voronoi(delaunay, points, points.length); + const voronoi = new Voronoi(delaunay, points, points.length); const chain = connectCenters(voronoi.vertices, s.pole[1]); const relaxed = chain.map(i => voronoi.vertices.p[i]).filter((p, i) => i%15 === 0 || i+1 === chain.length); paths.push([s.i, relaxed]); diff --git a/modules/voronoi.js b/modules/voronoi.js index f7b82292..7889b91e 100644 --- a/modules/voronoi.js +++ b/modules/voronoi.js @@ -1,82 +1,136 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.Voronoi = factory()); -}(this, (function () { 'use strict'; +class Voronoi { + /** + * Creates a Voronoi diagram from the given Delaunator, a list of points, and the number of points. The Voronoi diagram is constructed using (I think) the {@link https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm |Bowyer-Watson Algorithm} + * The {@link https://github.com/mapbox/delaunator/ |Delaunator} library uses {@link https://en.wikipedia.org/wiki/Doubly_connected_edge_list |half-edges} to represent the relationship between points and triangles. + * @param {{triangles: Uint32Array, halfedges: Int32Array}} delaunay A {@link https://github.com/mapbox/delaunator/blob/master/index.js |Delaunator} instance. + * @param {[number, number][]} points A list of coordinates. + * @param {number} pointsN The number of points. + */ + constructor(delaunay, points, pointsN) { + this.delaunay = delaunay; + this.points = points; + this.pointsN = pointsN; + this.cells = { v: [], c: [], b: [] }; // voronoi cells: v = cell vertices, c = adjacent cells, b = near-border cell + this.vertices = { p: [], v: [], c: [] }; // cells vertices: p = vertex coordinates, v = neighboring vertices, c = adjacent cells - var Voronoi = function Voronoi(delaunay, points, pointsN) { - const cells = {v: [], c: [], b: []}; // voronoi cells: v = cell vertices, c = adjacent cells, b = near-border cell - const vertices = {p: [], v: [], c: []}; // cells vertices: p = vertex coordinates, v = neighboring vertices, c = adjacent cells - for (let e=0; e < delaunay.triangles.length; e++) { + // Half-edges are the indices into the delaunator outputs: + // delaunay.triangles[e] gives the point ID where the half-edge starts + // delaunay.triangles[e] returns either the opposite half-edge in the adjacent triangle, or -1 if there's not an adjacent triangle. + for (let e = 0; e < this.delaunay.triangles.length; e++) { - const p = delaunay.triangles[nextHalfedge(e)]; - if (p < pointsN && !cells.c[p]) { - const edges = edgesAroundPoint(e); - cells.v[p] = edges.map(e => triangleOfEdge(e)); // cell: adjacent vertex - cells.c[p] = edges.map(e => delaunay.triangles[e]).filter(c => c < pointsN); // cell: adjacent valid cells - cells.b[p] = edges.length > cells.c[p].length ? 1 : 0; // cell: is border + const p = this.delaunay.triangles[this.nextHalfedge(e)]; + if (p < this.pointsN && !this.cells.c[p]) { + const edges = this.edgesAroundPoint(e); + this.cells.v[p] = edges.map(e => this.triangleOfEdge(e)); // cell: adjacent vertex + this.cells.c[p] = edges.map(e => this.delaunay.triangles[e]).filter(c => c < this.pointsN); // cell: adjacent valid cells + this.cells.b[p] = edges.length > this.cells.c[p].length ? 1 : 0; // cell: is border } - const t = triangleOfEdge(e); - if (!vertices.p[t]) { - vertices.p[t] = triangleCenter(t); // vertex: coordinates - vertices.v[t] = trianglesAdjacentToTriangle(t); // vertex: adjacent vertices - vertices.c[t] = pointsOfTriangle(t); // vertex: adjacent cells + const t = this.triangleOfEdge(e); + if (!this.vertices.p[t]) { + this.vertices.p[t] = this.triangleCenter(t); // vertex: coordinates + this.vertices.v[t] = this.trianglesAdjacentToTriangle(t); // vertex: adjacent vertices + this.vertices.c[t] = this.pointsOfTriangle(t); // vertex: adjacent cells } } - - function pointsOfTriangle(t) { - return edgesOfTriangle(t).map(e => delaunay.triangles[e]); - } - - function trianglesAdjacentToTriangle(t) { - let triangles = []; - for (let e of edgesOfTriangle(t)) { - let opposite = delaunay.halfedges[e]; - triangles.push(triangleOfEdge(opposite)); - } - return triangles; - } - - function edgesAroundPoint(start) { - let result = [], incoming = start; - do { - result.push(incoming); - const outgoing = nextHalfedge(incoming); - incoming = delaunay.halfedges[outgoing]; - } while (incoming !== -1 && incoming !== start && result.length < 20); - return result; - } - - function triangleCenter(t) { - let vertices = pointsOfTriangle(t).map(p => points[p]); - return circumcenter(vertices[0], vertices[1], vertices[2]); - } - - return {cells, vertices} - } - function edgesOfTriangle(t) {return [3*t, 3*t+1, 3*t+2];} + /** + * Gets the IDs of the points comprising the given triangle. Taken from {@link https://mapbox.github.io/delaunator/#triangle-to-points| the Delaunator docs.} + * @param {number} t The index of the triangle + * @returns {[number, number, number]} The IDs of the points comprising the given triangle. + */ + pointsOfTriangle(t) { + return this.edgesOfTriangle(t).map(edge => this.delaunay.triangles[edge]); + } - function triangleOfEdge(e) {return Math.floor(e/3);} + /** + * Identifies what triangles are adjacent to the given triangle. Taken from {@link https://mapbox.github.io/delaunator/#triangle-to-triangles| the Delaunator docs.} + * @param {number} t The index of the triangle + * @returns {number[]} The indices of the triangles that share half-edges with this triangle. + */ + trianglesAdjacentToTriangle(t) { + let triangles = []; + for (let edge of this.edgesOfTriangle(t)) { + let opposite = this.delaunay.halfedges[edge]; + triangles.push(this.triangleOfEdge(opposite)); + } + return triangles; + } - function nextHalfedge(e) {return (e % 3 === 2) ? e-2 : e+1;} + /** + * Gets the indices of all the incoming and outgoing half-edges that touch the given point. Taken from {@link https://mapbox.github.io/delaunator/#point-to-edges| the Delaunator docs.} + * @param {number} start The index of an incoming half-edge that leads to the desired point + * @returns {number[]} The indices of all half-edges (incoming or outgoing) that touch the point. + */ + edgesAroundPoint(start) { + const result = []; + let incoming = start; + do { + result.push(incoming); + const outgoing = this.nextHalfedge(incoming); + incoming = this.delaunay.halfedges[outgoing]; + } while (incoming !== -1 && incoming !== start && result.length < 20); + return result; + } - function prevHalfedge(e) {return (e % 3 === 0) ? e+2 : e-1;} + /** + * Returns the center of the triangle located at the given index. + * @param {number} t The index of the triangle + * @returns {[number, number]} + */ + triangleCenter(t) { + let vertices = this.pointsOfTriangle(t).map(p => this.points[p]); + return this.circumcenter(vertices[0], vertices[1], vertices[2]); + } - function circumcenter(a, b, c) { - let ad = a[0]*a[0] + a[1]*a[1], - bd = b[0]*b[0] + b[1]*b[1], - cd = c[0]*c[0] + c[1]*c[1]; - let D = 2 * (a[0] * (b[1] - c[1]) + b[0] * (c[1] - a[1]) + c[0] * (a[1] - b[1])); + /** + * Retrieves all of the half-edges for a specific triangle `t`. Taken from {@link https://mapbox.github.io/delaunator/#edge-and-triangle| the Delaunator docs.} + * @param {number} t The index of the triangle + * @returns {[number, number, number]} The edges of the triangle. + */ + edgesOfTriangle(t) { return [3 * t, 3 * t + 1, 3 * t + 2]; } + + /** + * Enables lookup of a triangle, given one of the half-edges of that triangle. Taken from {@link https://mapbox.github.io/delaunator/#edge-and-triangle| the Delaunator docs.} + * @param {number} e The index of the edge + * @returns {number} The index of the triangle + */ + triangleOfEdge(e) { return Math.floor(e / 3); } + + /** + * Moves to the next half-edge of a triangle, given the current half-edge's index. Taken from {@link https://mapbox.github.io/delaunator/#edge-to-edges| the Delaunator docs.} + * @param {number} e The index of the current half edge + * @returns {number} The index of the next half edge + */ + nextHalfedge(e) { return (e % 3 === 2) ? e - 2 : e + 1; } + + /** + * Moves to the previous half-edge of a triangle, given the current half-edge's index. Taken from {@link https://mapbox.github.io/delaunator/#edge-to-edges| the Delaunator docs.} + * @param {number} e The index of the current half edge + * @returns {number} The index of the previous half edge + */ + prevHalfedge(e) { return (e % 3 === 0) ? e + 2 : e - 1; } + + /** + * Finds the circumcenter of the triangle identified by points a, b, and c. Taken from {@link https://en.wikipedia.org/wiki/Circumscribed_circle#Circumcenter_coordinates| Wikipedia} + * @param {[number, number]} a The coordinates of the first point of the triangle + * @param {[number, number]} b The coordinates of the second point of the triangle + * @param {[number, number]} c The coordinates of the third point of the triangle + * @return {[number, number]} The coordinates of the circumcenter of the triangle. + */ + circumcenter(a, b, c) { + const [ax, ay] = a; + const [bx, by] = b; + const [cx, cy] = c; + const ad = ax * ax + ay * ay; + const bd = bx * bx + by * by; + const cd = cx * cx + cy * cy; + const D = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)); return [ - Math.floor(1/D * (ad * (b[1] - c[1]) + bd * (c[1] - a[1]) + cd * (a[1] - b[1]))), - Math.floor(1/D * (ad * (c[0] - b[0]) + bd * (a[0] - c[0]) + cd * (b[0] - a[0]))) + Math.floor(1 / D * (ad * (by - cy) + bd * (cy - ay) + cd * (ay - by))), + Math.floor(1 / D * (ad * (cx - bx) + bd * (ax - cx) + cd * (bx - ax))) ]; } - - return Voronoi; - -}))); \ No newline at end of file +} \ No newline at end of file