This commit is contained in:
Azgaar 2020-04-04 00:18:29 +03:00
parent 79e9a12d99
commit aab1b8eac6
12 changed files with 152 additions and 109 deletions

View file

@ -3473,6 +3473,15 @@
<p id="alertMessage">Warning!</p> <p id="alertMessage">Warning!</p>
</div> </div>
<dialog id="prompt" style="border: solid 1px #5e4fa2; user-select: none;">
<form method="dialog">
<div id="dialogText" style="padding-bottom: .4em; font-family: sans-serif"></div>
<input id="promptInput" type="number" step=.01 placeholder="type value" autocomplete="off" required>
<button type="submit" value="yes">Confirm</button>
<button value="no" formnovalidate>Cancel</button>
</form>
</dialog>
</div> </div>
<div id="notes"> <div id="notes">

20
main.js
View file

@ -254,11 +254,11 @@ function findBurgForMFCG(params) {
const cells = pack.cells, burgs = pack.burgs; 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) {console.error("Cannot select a burg for MFCG"); return;}
// used for selection
const size = +params.get("size"); const size = +params.get("size");
const name = params.get("name"); const coast = +params.get("coast");
let coast = +params.get("coast"); const port = +params.get("port");
let port = +params.get("port"); const river = +params.get("river");
let river = +params.get("river");
let selection = defineSelection(coast, port, river); let selection = defineSelection(coast, port, river);
if (!selection.length) 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 selected = d3.scan(selection, (a, b) => Math.abs(a.population - size) - Math.abs(b.population - size));
const b = selection[selected].i; const b = selection[selected].i;
if (!b) {console.error("Cannot select a burg for MFCG"); return;} 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 + "']"); const label = burgLabels.select("[data-id='" + b + "']");
if (label.size()) { if (label.size()) {
@ -290,6 +295,7 @@ function findBurgForMFCG(params) {
}); });
} }
burgs[b].MFCG = +seed;
zoomTo(burgs[b].x, burgs[b].y, 8, 1600); zoomTo(burgs[b].x, burgs[b].y, 8, 1600);
invokeActiveZooming(); invokeActiveZooming();
} }
@ -1242,7 +1248,7 @@ function addMarkers(number = 1) {
addMarker("mine", "⚒", 50, 50, 20); addMarker("mine", "⚒", 50, 50, 20);
const resources = {"salt":5, "gold":2, "silver":4, "copper":2, "iron":3, "lead":1, "tin":1}; 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 cell = hills.splice(Math.floor(Math.random() * hills.length), 1);
const x = cells.p[cell][0], y = cells.p[cell][1]; const x = cells.p[cell][0], y = cells.p[cell][1];
const id = getNextId("markerElement"); const id = getNextId("markerElement");

View file

@ -281,14 +281,17 @@ function editBurg(id) {
function openInMFCG(event) { function openInMFCG(event) {
const id = elSelected.attr("data-id"); const id = elSelected.attr("data-id");
const burg = pack.burgs[id]; const burg = pack.burgs[id];
const defSeed = seed + id.padStart(4, 0); const defSeed = +(seed + id.padStart(4, 0));
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const newSeed = prompt(`Please provide a Medieval Fantasy City Generator seed. `+ prompt(`Please provide a Medieval Fantasy City Generator seed. <br>
`Seed should be a number. Default seed is FMG map seed + burg id padded to 4 chars with zeros (${defSeed}). `+ Seed should be a number. Default seed is FMG map seed + burg id padded to 4 chars with zeros (${defSeed}). <br>
`Please note that if seed is custom, "Overworld" button from MFCG will open a different map`, burg.MFCG || 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 => {
if (newSeed) burg.MFCG = newSeed; else return; burg.MFCG = v;
} openMFCG();
});
} else openMFCG();
function openMFCG() {
const name = elSelected.text(); const name = elSelected.text();
const size = Math.max(Math.min(rn(burg.population), 65), 6); const size = Math.max(Math.min(rn(burg.population), 65), 6);
@ -304,23 +307,23 @@ function editBurg(id) {
const temple = +burg.temple; const temple = +burg.temple;
const shanty = +burg.shanty; 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}`; 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); openURL(url);
} }
}
function openInIAHG(event) { function openInIAHG(event) {
const id = elSelected.attr("data-id"); const id = elSelected.attr("data-id"), burg = pack.burgs[id], defSeed = `${seed}-b${id}`;
const burg = pack.burgs[id]; const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (burg.IAHG || defSeed));
const defSeed = `${seed}-b${id}`;
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+ prompt(`Please provide an Iron Arachne Heraldry Generator seed. <br>Default seed is a combination of FMG map seed and burg id (${defSeed})`,
`Default seed is a combination of FMG map seed and burg id (${defSeed})`, burg.IAHG || defSeed); {default:burg.IAHG || defSeed}, v => {
if (newSeed) burg.IAHG = newSeed; else return; if (v && v != defSeed) burg.IAHG = v;
} openIAHG();
});
const s = burg.IAHG || defSeed; } else openIAHG();
openURL("https://ironarachne.com/heraldry/" + s);
} }
function toggleRelocateBurg() { function toggleRelocateBurg() {

View file

@ -460,10 +460,10 @@ function editCultures() {
} }
function changeCode(d) { function changeCode(d) {
const code = prompt(`Please provide an abbreviation for culture: ${d.data.name}`, d.data.code); prompt(`Please provide an abbreviation for culture: ${d.data.name}`, {default:d.data.code}, v => {
if (!code) return; pack.cultures[d.data.i].code = v;
pack.cultures[d.data.i].code = code; nodes.select("g[data-id='"+d.data.i+"']").select("text").text(v);
nodes.select("g[data-id='"+d.data.i+"']").select("text").text(code); });
} }
} }

View file

@ -711,12 +711,13 @@ function editHeightmap() {
function setRange(event) { function setRange(event) {
if (event.target.value !== "interval") return; 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; prompt("Set a height interval. Avoid space, use hyphen as a separator", {default:"17-20"}, v => {
const opt = document.createElement("option"); const opt = document.createElement("option");
opt.value = opt.innerHTML = interval; opt.value = opt.innerHTML = v;
event.target.add(opt); event.target.add(opt);
event.target.value = interval; event.target.value = v;
});
} }
function selectTemplate(e) { function selectTemplate(e) {

View file

@ -76,14 +76,14 @@ function changePreset(preset) {
} }
function savePreset() { function savePreset() {
const preset = prompt("Please provide a preset name"); // preset name prompt("Please provide a preset name", {default:""}, preset => {
if (!preset) return;
presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort(); presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
layersPreset.add(new Option(preset, preset, false, true)); layersPreset.add(new Option(preset, preset, false, true));
localStorage.setItem("presets", JSON.stringify(presets)); localStorage.setItem("presets", JSON.stringify(presets));
localStorage.setItem("preset", preset); localStorage.setItem("preset", preset);
removePresetButton.style.display = "inline-block"; removePresetButton.style.display = "inline-block";
savePresetButton.style.display = "none"; savePresetButton.style.display = "none";
});
} }
function removePreset() { function removePreset() {

View file

@ -193,15 +193,15 @@ function editProvinces() {
function provinceOpenCOA(event, p) { function provinceOpenCOA(event, p) {
const defSeed = `${seed}-p${p}`; const defSeed = `${seed}-p${p}`;
const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.provinces[p].IAHG || defSeed));
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+ prompt(`Please provide an Iron Arachne Heraldry Generator seed. <br>Default seed is a combination of FMG map seed and province id (${defSeed})`,
`Default seed is a combination of FMG map seed and province id (${defSeed})`, pack.provinces[p].IAHG || defSeed); {default:pack.provinces[p].IAHG || defSeed}, v => {
if (newSeed && newSeed != defSeed) pack.provinces[p].IAHG = newSeed; else return; if (v && v != defSeed) pack.provinces[p].IAHG = v;
} openIAHG();
});
const s = pack.provinces[p].IAHG || defSeed; } else openIAHG();
openURL("https://ironarachne.com/heraldry/" + s);
} }
function capitalZoomIn(p) { function capitalZoomIn(p) {

View file

@ -450,10 +450,10 @@ function editReligions() {
} }
function changeCode(d) { function changeCode(d) {
const code = prompt(`Please provide an abbreviation for ${d.data.name}`, d.data.code); prompt(`Please provide an abbreviation for ${d.data.name}`, {default:d.data.code}, v => {
if (!code) return; pack.religions[d.data.i].code = v;
pack.religions[d.data.i].code = code; nodes.select("g[data-id='"+d.data.i+"']").select("text").text(v);
nodes.select("g[data-id='"+d.data.i+"']").select("text").text(code); });
} }
} }

View file

@ -307,15 +307,15 @@ function editStates() {
function stateOpenCOA(event, state) { function stateOpenCOA(event, state) {
const defSeed = `${seed}-s${state}`; const defSeed = `${seed}-s${state}`;
const openIAHG = () => openURL("https://ironarachne.com/heraldry/" + (pack.states[state].IAHG || defSeed));
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const newSeed = prompt(`Please provide an Iron Arachne Heraldry Generator seed. `+ prompt(`Please provide an Iron Arachne Heraldry Generator seed. <br>Default seed is a combination of FMG map seed and state id (${defSeed})`,
`Default seed is a combination of FMG map seed and province id (${defSeed})`, pack.states[state].IAHG || defSeed); {default:pack.states[state].IAHG || defSeed}, v => {
if (newSeed && newSeed != defSeed) pack.states[state].IAHG = newSeed; else return; if (v && v != defSeed) pack.states[state].IAHG = v;
} openIAHG();
});
const s = pack.states[state].IAHG || defSeed; } else openIAHG();
openURL("https://ironarachne.com/heraldry/" + s);
} }
function changePopulation(state) { function changePopulation(state) {

View file

@ -250,18 +250,14 @@ function regenerateMilitary() {
} }
function regenerateMarkers(event) { function regenerateMarkers(event) {
let number = gauss(1, .5, .3, 5, 2);
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const numberManual = prompt("Please provide markers number multiplier", 1); prompt("Please provide markers number multiplier", {default:1, step:.01, min:0, max:100}, v => {
if (numberManual === null || numberManual === "" || isNaN(+numberManual)) { if (v === null || v === "" || isNaN(+v)) return;
tip("The number provided is invalid, please try again and provide a valid number", false, "error", 4000); addNumberOfMarkers(Math.min(+v, 100));
return; });
} } else addNumberOfMarkers(gauss(1, .5, .3, 5, 2));
number = Math.min(+numberManual, 100);
}
function addNumberOfMarkers(number) {
// remove existing markers and assigned notes // remove existing markers and assigned notes
markers.selectAll("use").each(function() { markers.selectAll("use").each(function() {
const index = notes.findIndex(n => n.id === this.id); const index = notes.findIndex(n => n.id === this.id);
@ -269,24 +265,24 @@ function regenerateMarkers(event) {
}).remove(); }).remove();
addMarkers(number); addMarkers(number);
if (!layerIsOn("toggleMarkers")) toggleMarkers();
}
} }
function regenerateZones(event) { function regenerateZones(event) {
let number = gauss(1, .5, .6, 5, 2);
if (isCtrlClick(event)) { if (isCtrlClick(event)) {
const numberManual = prompt("Please provide zones number multiplier", 1); prompt("Please provide zones number multiplier", {default:1, step:.01, min:0, max:100}, v => {
if (numberManual === null || numberManual === "" || isNaN(+numberManual)) { if (v === null || v === "" || isNaN(+v)) return;
tip("The number provided is invalid, please try again and provide a valid number", false, "error", 4000); addNumberOfZones(Math.min(+v, 100));
return; });
} } else addNumberOfZones(gauss(1, .5, .6, 5, 2));
number = Math.min(+numberManual, 100);
}
function addNumberOfZones(number) {
zones.selectAll("g").remove(); // remove existing zones zones.selectAll("g").remove(); // remove existing zones
addZones(number); addZones(number);
if (document.getElementById("zonesEditorRefresh").offsetParent) zonesEditorRefresh.click(); if (document.getElementById("zonesEditorRefresh").offsetParent) zonesEditorRefresh.click();
if (!layerIsOn("toggleZones")) toggleZones();
}
} }
function unpressClickToAddButton() { function unpressClickToAddButton() {

View file

@ -41,8 +41,13 @@ function editUnits() {
function changeDistanceUnit() { function changeDistanceUnit() {
if (this.value === "custom_name") { if (this.value === "custom_name") {
const custom = prompt("Provide a custom name for distance unit"); prompt("Provide a custom name for a distance unit", {default:""}, custom => {
if (custom) this.options.add(new Option(custom, custom, false, true)); this.options.add(new Option(custom, custom, false, true));
lock("distanceUnit");
drawScaleBar();
calculateFriendlyGridSize();
});
return;
} }
lock("distanceUnit"); lock("distanceUnit");
@ -69,9 +74,11 @@ function editUnits() {
function changeHeightUnit() { function changeHeightUnit() {
if (this.value === "custom_name") { if (this.value === "custom_name") {
const custom = prompt("Provide a custom name for height unit"); prompt("Provide a custom name for a height unit", {default:""}, custom => {
if (custom) this.options.add(new Option(custom, custom, false, true)); this.options.add(new Option(custom, custom, false, true));
else this.value = "ft"; lock("heightUnit");
});
return;
} }
lock("heightUnit"); lock("heightUnit");

View file

@ -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'}); 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 // 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)}}}(); !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)}}}();