diff --git a/index.html b/index.html
index 2a2a7ce9..e6eb9d4d 100644
--- a/index.html
+++ b/index.html
@@ -3473,6 +3473,15 @@
Warning!
+
+
diff --git a/main.js b/main.js
index 0766bddc..40675639 100644
--- a/main.js
+++ b/main.js
@@ -254,11 +254,11 @@ function findBurgForMFCG(params) {
const cells = pack.cells, burgs = pack.burgs;
if (pack.burgs.length < 2) {console.error("Cannot select a burg for MFCG"); return;}
+ // used for selection
const size = +params.get("size");
- const name = params.get("name");
- let coast = +params.get("coast");
- let port = +params.get("port");
- let river = +params.get("river");
+ const coast = +params.get("coast");
+ const port = +params.get("port");
+ const river = +params.get("river");
let selection = defineSelection(coast, port, river);
if (!selection.length) selection = defineSelection(coast, !port, !river);
@@ -278,8 +278,13 @@ function findBurgForMFCG(params) {
const selected = d3.scan(selection, (a, b) => Math.abs(a.population - size) - Math.abs(b.population - size));
const b = selection[selected].i;
if (!b) {console.error("Cannot select a burg for MFCG"); return;}
- if (size) burgs[b].population = size;
- if (name) burgs[b].name = name;
+
+ const referrer = new URL(document.referrer).searchParams;
+ for (let p of referrer) {
+ if (p[0] === "size") burgs[b].population = +p[1]; else
+ if (p[0] === "shantytown") burgs[b].shanty = +p[1]; else
+ burgs[b][p[0]] = p[1];
+ }
const label = burgLabels.select("[data-id='" + b + "']");
if (label.size()) {
@@ -290,6 +295,7 @@ function findBurgForMFCG(params) {
});
}
+ burgs[b].MFCG = +seed;
zoomTo(burgs[b].x, burgs[b].y, 8, 1600);
invokeActiveZooming();
}
@@ -1242,7 +1248,7 @@ function addMarkers(number = 1) {
addMarker("mine", "⚒", 50, 50, 20);
const resources = {"salt":5, "gold":2, "silver":4, "copper":2, "iron":3, "lead":1, "tin":1};
- while (count) {
+ while (count && hills.length) {
const cell = hills.splice(Math.floor(Math.random() * hills.length), 1);
const x = cells.p[cell][0], y = cells.p[cell][1];
const id = getNextId("markerElement");
diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js
index 8f6c1ecb..c2e26efe 100644
--- a/modules/ui/burg-editor.js
+++ b/modules/ui/burg-editor.js
@@ -281,46 +281,49 @@ function editBurg(id) {
function openInMFCG(event) {
const id = elSelected.attr("data-id");
const burg = pack.burgs[id];
- const defSeed = seed + id.padStart(4, 0);
+ const defSeed = +(seed + id.padStart(4, 0));
if (isCtrlClick(event)) {
- const newSeed = prompt(`Please provide a Medieval Fantasy City Generator seed. `+
- `Seed should be a number. Default seed is FMG map seed + burg id padded to 4 chars with zeros (${defSeed}). `+
- `Please note that if seed is custom, "Overworld" button from MFCG will open a different map`, burg.MFCG || defSeed);
- if (newSeed) burg.MFCG = newSeed; else return;
+ prompt(`Please provide a Medieval Fantasy City Generator seed.
+ Seed should be a number. Default seed is FMG map seed + burg id padded to 4 chars with zeros (${defSeed}).
+ Please note that if seed is custom, "Overworld" button from MFCG will open a different map`, {default:burg.MFCG||defSeed, step:1, min:1, max:1e13-1}, v => {
+ burg.MFCG = v;
+ openMFCG();
+ });
+ } else openMFCG();
+
+ function openMFCG() {
+ const name = elSelected.text();
+ const size = Math.max(Math.min(rn(burg.population), 65), 6);
+
+ const s = burg.MFCG || defSeed;
+ const cell = burg.cell;
+ const hub = +pack.cells.road[cell] > 50;
+ const river = pack.cells.r[cell] ? 1 : 0;
+
+ const coast = +burg.port;
+ const citadel = +burg.citadel;
+ const walls = +burg.walls;
+ const plaza = +burg.plaza;
+ const temple = +burg.temple;
+ const shanty = +burg.shanty;
+
+ const site = "http://fantasycities.watabou.ru/";
+ const url = `${site}?name=${name}&size=${size}&seed=${s}&hub=${hub}&random=0&continuous=0&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}`;
+ openURL(url);
}
-
- const name = elSelected.text();
- const size = Math.max(Math.min(rn(burg.population), 65), 6);
-
- const s = burg.MFCG || defSeed;
- const cell = burg.cell;
- const hub = +pack.cells.road[cell] > 50;
- const river = pack.cells.r[cell] ? 1 : 0;
-
- const coast = +burg.port;
- const citadel = +burg.citadel;
- const walls = +burg.walls;
- const plaza = +burg.plaza;
- const temple = +burg.temple;
- const shanty = +burg.shanty;
-
- const url = `http://fantasycities.watabou.ru/?name=${name}&size=${size}&seed=${s}&hub=${hub}&random=0&continuous=0&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}`;
- openURL(url);
}
function openInIAHG(event) {
- const id = elSelected.attr("data-id");
- const burg = pack.burgs[id];
- const defSeed = `${seed}-b${id}`;
+ const id = elSelected.attr("data-id"), burg = pack.burgs[id], defSeed = `${seed}-b${id}`;
+ const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (burg.IAHG || defSeed));
if (isCtrlClick(event)) {
- const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+
- `Default seed is a combination of FMG map seed and burg id (${defSeed})`, burg.IAHG || defSeed);
- if (newSeed) burg.IAHG = newSeed; else return;
- }
-
- const s = burg.IAHG || defSeed;
- openURL("https://ironarachne.com/heraldry/" + s);
+ prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and burg id (${defSeed})`,
+ {default:burg.IAHG || defSeed}, v => {
+ if (v && v != defSeed) burg.IAHG = v;
+ openIAHG();
+ });
+ } else openIAHG();
}
function toggleRelocateBurg() {
diff --git a/modules/ui/cultures-editor.js b/modules/ui/cultures-editor.js
index 88820810..369083af 100644
--- a/modules/ui/cultures-editor.js
+++ b/modules/ui/cultures-editor.js
@@ -460,10 +460,10 @@ function editCultures() {
}
function changeCode(d) {
- const code = prompt(`Please provide an abbreviation for culture: ${d.data.name}`, d.data.code);
- if (!code) return;
- pack.cultures[d.data.i].code = code;
- nodes.select("g[data-id='"+d.data.i+"']").select("text").text(code);
+ prompt(`Please provide an abbreviation for culture: ${d.data.name}`, {default:d.data.code}, v => {
+ pack.cultures[d.data.i].code = v;
+ nodes.select("g[data-id='"+d.data.i+"']").select("text").text(v);
+ });
}
}
diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js
index 7648f0c9..66f8a0c6 100644
--- a/modules/ui/heightmap-editor.js
+++ b/modules/ui/heightmap-editor.js
@@ -711,12 +711,13 @@ function editHeightmap() {
function setRange(event) {
if (event.target.value !== "interval") return;
- const interval = prompt("Set a height interval. E.g. '17-20'. Avoid space, use hyphen as a separator");
- if (!interval || interval === "") return;
- const opt = document.createElement("option");
- opt.value = opt.innerHTML = interval;
- event.target.add(opt);
- event.target.value = interval;
+
+ prompt("Set a height interval. Avoid space, use hyphen as a separator", {default:"17-20"}, v => {
+ const opt = document.createElement("option");
+ opt.value = opt.innerHTML = v;
+ event.target.add(opt);
+ event.target.value = v;
+ });
}
function selectTemplate(e) {
diff --git a/modules/ui/layers.js b/modules/ui/layers.js
index bf5e6bf4..20970df9 100644
--- a/modules/ui/layers.js
+++ b/modules/ui/layers.js
@@ -76,14 +76,14 @@ function changePreset(preset) {
}
function savePreset() {
- const preset = prompt("Please provide a preset name"); // preset name
- if (!preset) return;
- presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
- layersPreset.add(new Option(preset, preset, false, true));
- localStorage.setItem("presets", JSON.stringify(presets));
- localStorage.setItem("preset", preset);
- removePresetButton.style.display = "inline-block";
- savePresetButton.style.display = "none";
+ prompt("Please provide a preset name", {default:""}, preset => {
+ presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
+ layersPreset.add(new Option(preset, preset, false, true));
+ localStorage.setItem("presets", JSON.stringify(presets));
+ localStorage.setItem("preset", preset);
+ removePresetButton.style.display = "inline-block";
+ savePresetButton.style.display = "none";
+ });
}
function removePreset() {
diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js
index 5d6d1912..bc7b6379 100644
--- a/modules/ui/provinces-editor.js
+++ b/modules/ui/provinces-editor.js
@@ -193,15 +193,15 @@ function editProvinces() {
function provinceOpenCOA(event, p) {
const defSeed = `${seed}-p${p}`;
+ const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.provinces[p].IAHG || defSeed));
if (isCtrlClick(event)) {
- const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+
- `Default seed is a combination of FMG map seed and province id (${defSeed})`, pack.provinces[p].IAHG || defSeed);
- if (newSeed && newSeed != defSeed) pack.provinces[p].IAHG = newSeed; else return;
- }
-
- const s = pack.provinces[p].IAHG || defSeed;
- openURL("https://ironarachne.com/heraldry/" + s);
+ prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and province id (${defSeed})`,
+ {default:pack.provinces[p].IAHG || defSeed}, v => {
+ if (v && v != defSeed) pack.provinces[p].IAHG = v;
+ openIAHG();
+ });
+ } else openIAHG();
}
function capitalZoomIn(p) {
diff --git a/modules/ui/religions-editor.js b/modules/ui/religions-editor.js
index c4ad337b..704ff531 100644
--- a/modules/ui/religions-editor.js
+++ b/modules/ui/religions-editor.js
@@ -450,10 +450,10 @@ function editReligions() {
}
function changeCode(d) {
- const code = prompt(`Please provide an abbreviation for ${d.data.name}`, d.data.code);
- if (!code) return;
- pack.religions[d.data.i].code = code;
- nodes.select("g[data-id='"+d.data.i+"']").select("text").text(code);
+ prompt(`Please provide an abbreviation for ${d.data.name}`, {default:d.data.code}, v => {
+ pack.religions[d.data.i].code = v;
+ nodes.select("g[data-id='"+d.data.i+"']").select("text").text(v);
+ });
}
}
diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js
index a534001d..92af1fbf 100644
--- a/modules/ui/states-editor.js
+++ b/modules/ui/states-editor.js
@@ -307,15 +307,15 @@ function editStates() {
function stateOpenCOA(event, state) {
const defSeed = `${seed}-s${state}`;
+ const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.states[state].IAHG || defSeed));
if (isCtrlClick(event)) {
- const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+
- `Default seed is a combination of FMG map seed and province id (${defSeed})`, pack.states[state].IAHG || defSeed);
- if (newSeed && newSeed != defSeed) pack.states[state].IAHG = newSeed; else return;
- }
-
- const s = pack.states[state].IAHG || defSeed;
- openURL("https://ironarachne.com/heraldry/" + s);
+ prompt(`Please provide an Iron Arachne Heraldry Generator seed.
Default seed is a combination of FMG map seed and state id (${defSeed})`,
+ {default:pack.states[state].IAHG || defSeed}, v => {
+ if (v && v != defSeed) pack.states[state].IAHG = v;
+ openIAHG();
+ });
+ } else openIAHG();
}
function changePopulation(state) {
diff --git a/modules/ui/tools.js b/modules/ui/tools.js
index 6ca05b78..5104cfb1 100644
--- a/modules/ui/tools.js
+++ b/modules/ui/tools.js
@@ -250,43 +250,39 @@ function regenerateMilitary() {
}
function regenerateMarkers(event) {
- let number = gauss(1, .5, .3, 5, 2);
-
if (isCtrlClick(event)) {
- const numberManual = prompt("Please provide markers number multiplier", 1);
- if (numberManual === null || numberManual === "" || isNaN(+numberManual)) {
- tip("The number provided is invalid, please try again and provide a valid number", false, "error", 4000);
- return;
- }
+ prompt("Please provide markers number multiplier", {default:1, step:.01, min:0, max:100}, v => {
+ if (v === null || v === "" || isNaN(+v)) return;
+ addNumberOfMarkers(Math.min(+v, 100));
+ });
+ } else addNumberOfMarkers(gauss(1, .5, .3, 5, 2));
- number = Math.min(+numberManual, 100);
+ function addNumberOfMarkers(number) {
+ // remove existing markers and assigned notes
+ markers.selectAll("use").each(function() {
+ const index = notes.findIndex(n => n.id === this.id);
+ if (index != -1) notes.splice(index, 1);
+ }).remove();
+
+ addMarkers(number);
+ if (!layerIsOn("toggleMarkers")) toggleMarkers();
}
-
- // remove existing markers and assigned notes
- markers.selectAll("use").each(function() {
- const index = notes.findIndex(n => n.id === this.id);
- if (index != -1) notes.splice(index, 1);
- }).remove();
-
- addMarkers(number);
}
function regenerateZones(event) {
- let number = gauss(1, .5, .6, 5, 2);
-
if (isCtrlClick(event)) {
- const numberManual = prompt("Please provide zones number multiplier", 1);
- if (numberManual === null || numberManual === "" || isNaN(+numberManual)) {
- tip("The number provided is invalid, please try again and provide a valid number", false, "error", 4000);
- return;
- }
+ prompt("Please provide zones number multiplier", {default:1, step:.01, min:0, max:100}, v => {
+ if (v === null || v === "" || isNaN(+v)) return;
+ addNumberOfZones(Math.min(+v, 100));
+ });
+ } else addNumberOfZones(gauss(1, .5, .6, 5, 2));
- number = Math.min(+numberManual, 100);
+ function addNumberOfZones(number) {
+ zones.selectAll("g").remove(); // remove existing zones
+ addZones(number);
+ if (document.getElementById("zonesEditorRefresh").offsetParent) zonesEditorRefresh.click();
+ if (!layerIsOn("toggleZones")) toggleZones();
}
-
- zones.selectAll("g").remove(); // remove existing zones
- addZones(number);
- if (document.getElementById("zonesEditorRefresh").offsetParent) zonesEditorRefresh.click();
}
function unpressClickToAddButton() {
diff --git a/modules/ui/units-editor.js b/modules/ui/units-editor.js
index 072cd653..d545c128 100644
--- a/modules/ui/units-editor.js
+++ b/modules/ui/units-editor.js
@@ -41,8 +41,13 @@ function editUnits() {
function changeDistanceUnit() {
if (this.value === "custom_name") {
- const custom = prompt("Provide a custom name for distance unit");
- if (custom) this.options.add(new Option(custom, custom, false, true));
+ prompt("Provide a custom name for a distance unit", {default:""}, custom => {
+ this.options.add(new Option(custom, custom, false, true));
+ lock("distanceUnit");
+ drawScaleBar();
+ calculateFriendlyGridSize();
+ });
+ return;
}
lock("distanceUnit");
@@ -69,9 +74,11 @@ function editUnits() {
function changeHeightUnit() {
if (this.value === "custom_name") {
- const custom = prompt("Provide a custom name for height unit");
- if (custom) this.options.add(new Option(custom, custom, false, true));
- else this.value = "ft";
+ prompt("Provide a custom name for a height unit", {default:""}, custom => {
+ this.options.add(new Option(custom, custom, false, true));
+ lock("heightUnit");
+ });
+ return;
}
lock("heightUnit");
diff --git a/modules/utils.js b/modules/utils.js
index 463fb0be..a28db030 100644
--- a/modules/utils.js
+++ b/modules/utils.js
@@ -608,5 +608,26 @@ function generateDate(from = 100, to = 1000) {
return new Date(rand(from, to),rand(12),rand(31)).toLocaleDateString("en", {year:'numeric', month:'long', day:'numeric'});
}
+// prompt replacer (prompt does not work in Electron)
+window.prompt = function(dialogText = "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;}
+ const modal = document.getElementById("prompt");
+ const input = modal.querySelector("#promptInput");
+ modal.querySelector("#dialogText").innerHTML = dialogText;
+ const type = typeof(options.default) === "number" ? "number" : "text";
+ input.type = type;
+ if (options.step !== undefined) input.step = options.step;
+ if (options.min !== undefined) input.min = options.min;
+ if (options.max !== undefined) input.max = options.max;
+ input.placeholder = "type a " + type;
+ input.value = options.default;
+ modal.showModal();
+
+ modal.addEventListener("close", () => {
+ if (callback && modal.returnValue === "yes") callback(input.value);
+ input.value = modal.returnValue = "";
+ }, {once: true});
+}
+
// localStorageDB
!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("indexDB 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