diff --git a/modules/heightmap-templates.js b/config/heightmap-templates.js
similarity index 77%
rename from modules/heightmap-templates.js
rename to config/heightmap-templates.js
index 7e0cd20c..29738609 100644
--- a/modules/heightmap-templates.js
+++ b/config/heightmap-templates.js
@@ -1,6 +1,6 @@
"use strict";
-window.HeightmapTemplates = (function () {
+const heightmapTemplates = (function () {
const volcano = `Hill 1 90-100 44-56 40-60
Multiply 0.8 50-100 0 0
Range 1.5 30-55 45-55 40-60
@@ -148,20 +148,19 @@ window.HeightmapTemplates = (function () {
Range 6-8 40-50 5-95 10-90`;
return {
- volcano,
- highIsland,
- lowIsland,
- continents,
- archipelago,
- atoll,
- mediterranean,
- peninsula,
- peninsula,
- pangea,
- isthmus,
- shattered,
- taklamakan,
- oldWorld,
- fractious
+ volcano: {id: 0, name: "Volcano", template: volcano, probability: 3},
+ highIsland: {id: 1, name: "High Island", template: highIsland, probability: 19},
+ lowIsland: {id: 2, name: "Low Island", template: lowIsland, probability: 9},
+ continents: {id: 3, name: "Continents", template: continents, probability: 16},
+ archipelago: {id: 4, name: "Archipelago", template: archipelago, probability: 18},
+ atoll: {id: 5, name: "Atoll", template: atoll, probability: 1},
+ mediterranean: {id: 6, name: "Mediterranean", template: mediterranean, probability: 5},
+ peninsula: {id: 7, name: "Peninsula", template: peninsula, probability: 3},
+ pangea: {id: 8, name: "Pangea", template: pangea, probability: 5},
+ isthmus: {id: 9, name: "Isthmus", template: isthmus, probability: 2},
+ shattered: {id: 10, name: "Shattered", template: shattered, probability: 7},
+ taklamakan: {id: 11, name: "Taklamakan", template: taklamakan, probability: 1},
+ oldWorld: {id: 12, name: "Old World", template: oldWorld, probability: 8},
+ fractious: {id: 13, name: "Fractious", template: fractious, probability: 3}
};
})();
diff --git a/config/precreated-heightmaps.js b/config/precreated-heightmaps.js
new file mode 100644
index 00000000..22f45abd
--- /dev/null
+++ b/config/precreated-heightmaps.js
@@ -0,0 +1,27 @@
+"use strict";
+
+const precreatedHeightmaps = {
+ "africa-centric": {id: 0, name: "Africa Centric"},
+ arabia: {id: 1, name: "Arabia"},
+ atlantics: {id: 2, name: "Atlantics"},
+ britain: {id: 3, name: "Britain"},
+ caribbean: {id: 4, name: "Caribbean"},
+ "east-asia": {id: 5, name: "East Asia"},
+ eurasia: {id: 6, name: "Eurasia"},
+ europe: {id: 7, name: "Europe"},
+ "europe-accented": {id: 8, name: "Europe Accented"},
+ "europe-and-central-asia": {id: 9, name: "Europe and Central Asia"},
+ "europe-central": {id: 10, name: "Europe Central"},
+ "europe-north": {id: 11, name: "Europe North"},
+ greenland: {id: 12, name: "Greenland"},
+ hellenica: {id: 13, name: "Hellenica"},
+ iceland: {id: 14, name: "Iceland"},
+ "indian-ocean": {id: 15, name: "Indian Ocean"},
+ "mediterranean-sea": {id: 16, name: "Mediterranean Sea"},
+ "middle-east": {id: 17, name: "Middle East"},
+ "north-america": {id: 18, name: "North America"},
+ "us-centric": {id: 19, name: "US-centric"},
+ "us-mainland": {id: 20, name: "US Mainland"},
+ world: {id: 21, name: "World"},
+ "world-from-pacific": {id: 22, name: "World from Pacific"}
+};
diff --git a/index.html b/index.html
index d027e45c..c3ef5ab1 100644
--- a/index.html
+++ b/index.html
@@ -1324,53 +1324,9 @@
Heightmap |
-
- |
-
-
+
|
+ |
@@ -6133,7 +6089,8 @@
-
+
+
diff --git a/main.js b/main.js
index cbd67e94..7a13bd5d 100644
--- a/main.js
+++ b/main.js
@@ -899,7 +899,7 @@ function addLakesInDeepDepressions() {
// near sea lakes usually get a lot of water inflow, most of them should brake threshold and flow out to sea (see Ancylus Lake)
function openNearSeaLakes() {
- if (templateInput.value === "Atoll") return; // no need for Atolls
+ if (byId("templateInput").value === "Atoll") return; // no need for Atolls
const cells = grid.cells;
const features = grid.features;
@@ -944,7 +944,7 @@ function defineMapSize() {
if (randomize || !locked("latitude")) latitudeOutput.value = latitudeInput.value = rn(latitude);
function getSizeAndLatitude() {
- const template = document.getElementById("templateInput").value; // heightmap template
+ const template = byId("templateInput").value; // heightmap template
if (template === "africa-centric") return [45, 53];
if (template === "arabia") return [20, 35];
@@ -1921,11 +1921,14 @@ function addZones(number = 1) {
// show map stats on generation complete
function showStatistics() {
- const template = templateInput.options[templateInput.selectedIndex].text;
- const templateRandom = locked("template") ? "" : "(random)";
+ const heightmap = byId("templateInput").value;
+ const isTemplate = heightmap in heightmapTemplates;
+ const heightmapType = isTemplate ? "template" : "precreated";
+ const isRandomTemplate = isTemplate && !locked("template") ? "random " : "";
+
const stats = ` Seed: ${seed}
- Canvas size: ${graphWidth}x${graphHeight}
- Template: ${template} ${templateRandom}
+ Canvas size: ${graphWidth}x${graphHeight} px
+ Heightmap: ${heightmap} (${isRandomTemplate}${heightmapType})
Points: ${grid.points.length}
Cells: ${pack.cells.i.length}
Map size: ${mapSizeOutput.value}%
@@ -1937,7 +1940,7 @@ function showStatistics() {
Cultures: ${pack.cultures.length - 1}`;
mapId = Date.now(); // unique map id is it's creation date number
- mapHistory.push({seed, width: graphWidth, height: graphHeight, template, created: mapId});
+ mapHistory.push({seed, width: graphWidth, height: graphHeight, template: heightmap, created: mapId});
INFO && console.log(stats);
}
diff --git a/modules/dynamic/heightmap-selection.js b/modules/dynamic/heightmap-selection.js
index 7b7a0412..15f62ce4 100644
--- a/modules/dynamic/heightmap-selection.js
+++ b/modules/dynamic/heightmap-selection.js
@@ -1,46 +1,3 @@
-const templates = [
- {id: "volcano", name: "Volcano"},
- {id: "highIsland", name: "High Island"},
- {id: "lowIsland", name: "Low Island"},
- {id: "continents", name: "Continents"},
- {id: "archipelago", name: "Archipelago"},
- {id: "atoll", name: "Atoll"},
- {id: "mediterranean", name: "Mediterranean"},
- {id: "peninsula", name: "Peninsula"},
- {id: "pangea", name: "Pangea"},
- {id: "isthmus", name: "Isthmus"},
- {id: "shattered", name: "Shattered"},
- {id: "taklamakan", name: "Taklamakan"},
- {id: "oldWorld", name: "Old World"},
- {id: "fractious", name: "Fractious"}
-];
-
-const heightmaps = [
- {id: "africa-centric", name: "Africa Centric"},
- {id: "arabia", name: "Arabia"},
- {id: "atlantics", name: "Atlantics"},
- {id: "britain", name: "Britain"},
- {id: "caribbean", name: "Caribbean"},
- {id: "east-asia", name: "East Asia"},
- {id: "eurasia", name: "Eurasia"},
- {id: "europe", name: "Europe"},
- {id: "europe-accented", name: "Europe Accented"},
- {id: "europe-and-central-asia", name: "Europe and Central Asia"},
- {id: "europe-central", name: "Europe Central"},
- {id: "europe-north", name: "Europe North"},
- {id: "greenland", name: "Greenland"},
- {id: "hellenica", name: "Hellenica"},
- {id: "iceland", name: "Iceland"},
- {id: "indian-ocean", name: "Indian Ocean"},
- {id: "mediterranean-sea", name: "Mediterranean Sea"},
- {id: "middle-east", name: "Middle East"},
- {id: "north-america", name: "North America"},
- {id: "us-centric", name: "US-centric"},
- {id: "us-mainland", name: "US Mainland"},
- {id: "world", name: "World"},
- {id: "world-from-pacific", name: "World from Pacific"}
-];
-
const initialSeed = generateSeed();
appendStyleSheet();
insertEditorHtml();
@@ -62,19 +19,20 @@ export function open() {
},
Select: function () {
const id = getSelected();
- $templateInput.value = id;
+ applyOption($templateInput, id, getName(id));
lock("template");
+
$(this).dialog("close");
},
"New Map": function () {
const id = getSelected();
- $templateInput.value = id;
+ applyOption($templateInput, id, getName(id));
lock("template");
const seed = getSeed();
Math.random = aleaPRNG(seed);
-
regeneratePrompt({seed});
+
$(this).dialog("close");
}
}
@@ -208,13 +166,14 @@ function insertEditorHtml() {
byId("dialogs").insertAdjacentHTML("beforeend", heightmapSelectionHtml);
const sections = document.getElementsByClassName("heightmap-selection_container");
- sections[0].innerHTML = templates
- .map(({id, name}) => {
+ sections[0].innerHTML = Object.keys(heightmapTemplates)
+ .map(key => {
+ const name = heightmapTemplates[key].name;
Math.random = aleaPRNG(initialSeed);
- const heights = generateHeightmap(id);
+ const heights = generateHeightmap(key);
const dataUrl = drawHeights(heights);
- return /* html */ `
+ return /* html */ `
${name}
@@ -224,11 +183,12 @@ function insertEditorHtml() {
})
.join("");
- sections[1].innerHTML = heightmaps
- .map(({id, name}) => {
- drawPrecreatedHeightmap(id);
+ sections[1].innerHTML = Object.keys(precreatedHeightmaps)
+ .map(key => {
+ const name = precreatedHeightmaps[key].name;
+ drawPrecreatedHeightmap(key);
- return /* html */ `
+ return /* html */ `
${name}
`;
@@ -271,6 +231,11 @@ function getSeed() {
return byId("heightmapSelection").querySelector(".selected")?.dataset?.seed;
}
+function getName(id) {
+ const isTemplate = id in heightmapTemplates;
+ return isTemplate ? heightmapTemplates[id].name : precreatedHeightmaps[id].name;
+}
+
function drawHeights(heights) {
const canvas = document.createElement("canvas");
canvas.width = grid.cellsX;
@@ -325,7 +290,7 @@ function redrawAll() {
const {id, seed} = article.dataset;
Math.random = aleaPRNG(seed);
- const isTemplate = id in HeightmapTemplates;
+ const isTemplate = id in heightmapTemplates;
if (isTemplate) drawTemplatePreview(id);
else drawPrecreatedHeightmap(id);
}
diff --git a/modules/heightmap-generator.js b/modules/heightmap-generator.js
index 71f2ea2d..bb4c0100 100644
--- a/modules/heightmap-generator.js
+++ b/modules/heightmap-generator.js
@@ -8,7 +8,7 @@ window.HeightmapGenerator = (function () {
const cleanup = () => (heights = null);
const fromTemplate = template => {
- const templateString = HeightmapTemplates[template];
+ const templateString = heightmapTemplates[template]?.template || "";
const steps = templateString.split("\n");
if (!steps.length) throw new Error(`Heightmap template: no steps. Template: ${template}. Steps: ${steps}`);
@@ -52,7 +52,7 @@ window.HeightmapGenerator = (function () {
const id = byId("templateInput").value;
resetHeights();
- const isTemplate = id in HeightmapTemplates;
+ const isTemplate = id in heightmapTemplates;
grid.cells.h = isTemplate ? fromTemplate(id) : await fromPrecreated(id);
cleanup();
diff --git a/modules/ui/general.js b/modules/ui/general.js
index 1b63dbac..7cb0f5c3 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -3,7 +3,7 @@
// fit full-screen map if window is resized
window.addEventListener("resize", function (e) {
- if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) return;
+ if (stored("mapWidth") && stored("mapHeight")) return;
mapWidthInput.value = window.innerWidth;
mapHeightInput.value = window.innerHeight;
changeMapSize();
@@ -414,7 +414,7 @@ document.querySelectorAll("[data-locked]").forEach(function (e) {
// lock option
function lock(id) {
const input = document.querySelector('[data-stored="' + id + '"]');
- if (input) localStorage.setItem(id, input.value);
+ if (input) store(id, input.value);
const el = document.getElementById("lock_" + id);
if (!el) return;
el.dataset.locked = 1;
@@ -436,9 +436,14 @@ function locked(id) {
return lockEl.dataset.locked == 1;
}
-// check if option is stored in localStorage
-function stored(option) {
- return localStorage.getItem(option);
+// return key value stored in localStorage or null
+function stored(key) {
+ return localStorage.getItem(key) || null;
+}
+
+// store key value in localStorage
+function store(key, value) {
+ return localStorage.setItem(key, value);
}
// assign skeaker behaviour
@@ -458,10 +463,10 @@ function speak(text) {
}
// apply drop-down menu option. If the value is not in options, add it
-function applyOption(select, id, name = id) {
- const custom = !Array.from(select.options).some(o => o.value == id);
- if (custom) select.options.add(new Option(name, id));
- select.value = id;
+function applyOption($select, value, name = value) {
+ const isExisting = Array.from($select.options).some(o => o.value === value);
+ if (!isExisting) $select.options.add(new Option(name, value));
+ $select.value = value;
}
// show info about the generator in a popup
diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js
index 69d98184..beb34ae5 100644
--- a/modules/ui/heightmap-editor.js
+++ b/modules/ui/heightmap-editor.js
@@ -921,7 +921,7 @@ function editHeightmap(options) {
body.setAttribute("data-changed", 0);
body.innerHTML = "";
- const templateString = HeightmapTemplates[template];
+ const templateString = heightmapTemplates[template]?.template;
if (!templateString) return;
const steps = templateString.split("\n");
diff --git a/modules/ui/options.js b/modules/ui/options.js
index 260cdea5..888571c7 100644
--- a/modules/ui/options.js
+++ b/modules/ui/options.js
@@ -6,14 +6,14 @@ $("#exitCustomization").draggable({handle: "div"});
$("#mapLayers").disableSelection();
// remove glow if tip is aknowledged
-if (localStorage.getItem("disable_click_arrow_tooltip")) {
+if (stored("disable_click_arrow_tooltip")) {
clearMainTip();
optionsTrigger.classList.remove("glow");
}
// Show options pane on trigger click
function showOptions(event) {
- if (!localStorage.getItem("disable_click_arrow_tooltip")) {
+ if (!stored("disable_click_arrow_tooltip")) {
clearMainTip();
localStorage.setItem("disable_click_arrow_tooltip", true);
optionsTrigger.classList.remove("glow");
@@ -81,12 +81,12 @@ async function showSupporters() {
}
// on any option or dialog change
-document.getElementById("options").addEventListener("change", checkIfStored);
-document.getElementById("dialogs").addEventListener("change", checkIfStored);
+document.getElementById("options").addEventListener("change", storeValueIfRequired);
+document.getElementById("dialogs").addEventListener("change", storeValueIfRequired);
document.getElementById("options").addEventListener("input", updateOutputToFollowInput);
document.getElementById("dialogs").addEventListener("input", updateOutputToFollowInput);
-function checkIfStored(ev) {
+function storeValueIfRequired(ev) {
if (ev.target.dataset.stored) lock(ev.target.dataset.stored);
}
@@ -142,7 +142,7 @@ optionsContent.addEventListener("click", function (event) {
else if (id === "optionsMapHistory") showSeedHistoryDialog();
else if (id === "optionsCopySeed") copyMapURL();
else if (id === "optionsEraRegenerate") regenerateEra();
- else if (id === "templateSelectButton") openTemplateSelectionDialog();
+ else if (id === "templateInput") openTemplateSelectionDialog();
else if (id === "zoomExtentDefault") restoreDefaultZoomExtent();
else if (id === "translateExtent") toggleTranslateExtent(event.target);
else if (id === "speakerTest") testSpeaker();
@@ -233,7 +233,7 @@ const voiceInterval = setInterval(function () {
voices.forEach((voice, i) => {
select.options.add(new Option(voice.name, i, false));
});
- if (stored("speakerVoice")) select.value = localStorage.getItem("speakerVoice");
+ if (stored("speakerVoice")) select.value = stored("speakerVoice");
// se voice to store
else select.value = voices.findIndex(voice => voice.lang === "en-US"); // or to first found English-US
}, 1000);
@@ -273,13 +273,14 @@ function showSeedHistoryDialog() {
// generate map with historical seed
function restoreSeed(id) {
- if (mapHistory[id].seed == seed) return tip("The current map is already generated with this seed", null, "error");
+ const {seed, width, height, template} = mapHistory[id];
+ byId("optionsSeed").value = seed;
+ byId("mapWidthInput").value = width;
+ byId("mapHeightInput").value = height;
+ byId("templateInput").value = template;
- optionsSeed.value = mapHistory[id].seed;
- mapWidthInput.value = mapHistory[id].width;
- mapHeightInput.value = mapHistory[id].height;
- templateInput.value = mapHistory[id].template;
if (locked("template")) unlock("template");
+
regeneratePrompt();
}
@@ -457,43 +458,50 @@ function changeZoomExtent(value) {
zoom.scaleTo(svg, scale);
}
-// control stored options logic
+// restore options stored in localStorage
function applyStoredOptions() {
- if (!localStorage.getItem("mapWidth") || !localStorage.getItem("mapHeight")) {
+ if (!stored("mapWidth") || !stored("mapHeight")) {
mapWidthInput.value = window.innerWidth;
mapHeightInput.value = window.innerHeight;
}
- if (localStorage.getItem("distanceUnit")) applyOption(distanceUnitInput, localStorage.getItem("distanceUnit"));
- if (localStorage.getItem("heightUnit")) applyOption(heightUnit, localStorage.getItem("heightUnit"));
-
- for (let i = 0; i < localStorage.length; i++) {
- const stored = localStorage.key(i);
- const value = localStorage.getItem(stored);
-
- if (stored === "speakerVoice") continue;
- const input = document.getElementById(stored + "Input") || document.getElementById(stored);
- const output = document.getElementById(stored + "Output");
- if (input) input.value = value;
- if (output) output.value = value;
- lock(stored);
-
- // add saved style presets to options
- if (stored.slice(0, 5) === "style") applyOption(stylePreset, stored, stored.slice(5));
+ const heightmapId = stored("template");
+ if (heightmapId) {
+ const name = heightmapTemplates[heightmapId]?.name || precreatedHeightmaps[heightmapId]?.name || heightmapId;
+ applyOption(byId("templateInput"), heightmapId, name);
}
- if (localStorage.getItem("winds"))
+ if (stored("distanceUnit")) applyOption(distanceUnitInput, stored("distanceUnit"));
+ if (stored("heightUnit")) applyOption(heightUnit, stored("heightUnit"));
+
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+
+ if (key === "speakerVoice") continue;
+ const input = byId(key + "Input") || byId(key);
+ const output = byId(key + "Output");
+
+ const value = stored(key);
+ if (input) input.value = value;
+ if (output) output.value = value;
+ lock(key);
+
+ // add saved style presets to options
+ if (key.slice(0, 5) === "style") applyOption(stylePreset, key, key.slice(5));
+ }
+
+ if (stored("winds"))
options.winds = localStorage
.getItem("winds")
.split(",")
.map(w => +w);
- if (localStorage.getItem("military")) options.military = JSON.parse(localStorage.getItem("military"));
+ if (stored("military")) options.military = JSON.parse(stored("military"));
- if (localStorage.getItem("tooltipSize")) changeTooltipSize(localStorage.getItem("tooltipSize"));
- if (localStorage.getItem("regions")) changeStatesNumber(localStorage.getItem("regions"));
+ if (stored("tooltipSize")) changeTooltipSize(stored("tooltipSize"));
+ if (stored("regions")) changeStatesNumber(stored("regions"));
uiSizeInput.max = uiSizeOutput.max = getUImaxSize();
- if (localStorage.getItem("uiSize")) changeUIsize(localStorage.getItem("uiSize"));
+ if (stored("uiSize")) changeUIsize(stored("uiSize"));
else changeUIsize(minmax(rn(mapWidthInput.value / 1280, 1), 1, 2.5));
// search params overwrite stored and default options
@@ -503,8 +511,8 @@ function applyStoredOptions() {
if (width) mapWidthInput.value = width;
if (height) mapHeightInput.value = height;
- const transparency = localStorage.getItem("transparency") || 5;
- const themeColor = localStorage.getItem("themeColor");
+ const transparency = stored("transparency") || 5;
+ const themeColor = stored("themeColor");
changeDialogsTheme(themeColor, transparency);
setRendering(shapeRendering.value);
@@ -549,22 +557,13 @@ function randomizeOptions() {
// select heightmap template pseudo-randomly
function randomizeHeightmapTemplate() {
- const templates = {
- volcano: 3,
- highIsland: 19,
- lowIsland: 9,
- continents: 16,
- archipelago: 18,
- mediterranean: 5,
- peninsula: 3,
- pangea: 5,
- isthmus: 2,
- atoll: 1,
- shattered: 7,
- taklamakan: 1,
- oldWorld: 11
- };
- document.getElementById("templateInput").value = rw(templates);
+ const templates = {};
+ for (const key in heightmapTemplates) {
+ templates[key] = heightmapTemplates[key].probability || 0;
+ }
+ const template = rw(templates);
+ const name = heightmapTemplates[template].name;
+ applyOption(byId("templateInput"), template, name);
}
// select culture set pseudo-randomly