From c050353d70994fde58d387d48f9ccd72cb768d4d Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 2 Oct 2019 22:20:01 +0300 Subject: [PATCH] v1.1.09 --- index.css | 36 ++++-- index.html | 209 +++++++++++++++++++++++++++------ modules/burgs-and-states.js | 28 +++-- modules/names-generator.js | 6 +- modules/ui/biomes-editor.js | 24 ++++ modules/ui/burg-editor.js | 178 ++++++++++++++++++---------- modules/ui/burgs-editor.js | 63 ++++------ modules/ui/diplomacy-editor.js | 2 +- modules/ui/editors.js | 38 +++++- modules/ui/heightmap-editor.js | 26 +++- modules/ui/provinces-editor.js | 131 ++++++++++++++------- modules/ui/states-editor.js | 151 +++++++++++++----------- modules/ui/tools.js | 8 +- modules/ui/zones-editor.js | 3 +- modules/utils.js | 5 + 15 files changed, 626 insertions(+), 282 deletions(-) diff --git a/index.css b/index.css index 4f9c5df5..d2eee5a6 100644 --- a/index.css +++ b/index.css @@ -184,8 +184,7 @@ i.icon-lock { #riverEditor > *, #routeEditor > *, #labelEditor div, -#markerEditor div, -#burgEditor * { +#markerEditor div { display: inline-block; } @@ -1206,6 +1205,7 @@ div.states>.statePopulation { width: 3em; } +div.states .icon-pencil, div.states .icon-trash-empty, div.states .icon-eye, div.states .icon-pin { @@ -1244,7 +1244,6 @@ div.states>.small { div.states>.cultureName { width: 5em; - white-space: nowrap; } div.states>.culturePopulation { @@ -1301,10 +1300,6 @@ div.states span.inactive:hover { cursor: pointer; } -div.states > div.stateName { - width: 12em; -} - #burgsFooterPopulation { border: 0; width: 50px; @@ -1313,6 +1308,33 @@ div.states > div.stateName { line-height: 1.4em; } +#stateNameEditor input, +#provinceNameEditor input { + padding-left: .3em; +} + +#stateNameEditor div.label, +#provinceNameEditor div.label, +#burgBody div.label { + display: inline-block; + width: 5.5em; +} + +.burgFeature { + font-size: 1.2em; + padding: 1px 2px; + color: #555; + cursor: pointer; +} + +.burgFeature.inactive { + color: #ddd; +} + +.burgFeature.inactive:hover { + color: #abaaaa; +} + div.states>.religionName { width: 11em; } diff --git a/index.html b/index.html index 4aeec706..090da597 100644 --- a/index.html +++ b/index.html @@ -204,6 +204,9 @@ Port + + + @@ -1742,7 +1745,7 @@
-
+

Click to configure:

@@ -1753,11 +1756,19 @@ -
+
+

Click to overview:

+ + + + + +
+

Click to regenerate:

@@ -2249,36 +2260,56 @@
`; } @@ -103,6 +104,7 @@ function editBurgs() { body.querySelectorAll("div > input.burgPopulation").forEach(el => el.addEventListener("change", changeBurgPopulation)); body.querySelectorAll("div > span.icon-star-empty").forEach(el => el.addEventListener("click", toggleCapitalStatus)); body.querySelectorAll("div > span.icon-anchor").forEach(el => el.addEventListener("click", togglePortStatus)); + body.querySelectorAll("div > span.icon-pencil").forEach(el => el.addEventListener("click", openBurgEditor)); body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.addEventListener("click", triggerBurgRemove)); applySorting(burgsHeader); @@ -164,51 +166,38 @@ function editBurgs() { } function toggleCapitalStatus() { - const burg = +this.parentNode.parentNode.dataset.id, state = pack.burgs[burg].state; - if (pack.burgs[burg].capital) {tip("To change capital please assign a capital status to another burg", false, "error"); return;} - if (!state) {tip("Neutral lands do not have a capital", false, "error"); return;} - const old = pack.states[state].capital; - - // change statuses - pack.states[state].capital = burg; - pack.states[state].center = pack.burgs[burg].cell; - pack.burgs[burg].capital = true; - pack.burgs[old].capital = false; - moveBurgToGroup(burg, "cities"); - moveBurgToGroup(old, "towns"); - + const burg = +this.parentNode.parentNode.dataset.id; + toggleCapital(burg); burgsEditorAddLines(); } function togglePortStatus() { const burg = +this.parentNode.parentNode.dataset.id; - const anchor = document.querySelector("#anchors [data-id='" + burg + "']"); - if (anchor) anchor.remove(); + togglePort(burg); + if (this.classList.contains("inactive")) this.classList.remove("inactive"); + else this.classList.add("inactive"); + } - if (!pack.burgs[burg].port) { - const haven = pack.cells.haven[pack.burgs[burg].cell]; - const port = haven ? pack.cells.f[haven] : -1; - if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, "warn"); - pack.burgs[burg].port = port; - - const g = pack.burgs[burg].capital ? "cities" : "towns"; - const group = anchors.select("g#"+g); - const size = +group.attr("size"); - group.append("use").attr("xlink:href", "#icon-anchor").attr("data-id", burg) - .attr("x", rn(pack.burgs[burg].x - size * .47, 2)).attr("y", rn(pack.burgs[burg].y - size * .47, 2)) - .attr("width", size).attr("height", size); - } else { - pack.burgs[burg].port = 0; - } - - burgsEditorAddLines(); + function openBurgEditor() { + const burg = +this.parentNode.dataset.id; + editBurg(burg); } function triggerBurgRemove() { const burg = +this.parentNode.dataset.id; if (pack.burgs[burg].capital) {tip("You cannot remove the capital. Please change the capital first", false, "error"); return;} - removeBurg(burg); - burgsEditorAddLines(); + + alertMessage.innerHTML = "Are you sure you want to remove the burg?"; + $("#alert").dialog({resizable: false, title: "Remove burg", + buttons: { + Remove: function() { + $(this).dialog("close"); + removeBurg(burg); + burgsEditorAddLines(); + }, + Cancel: function() {$(this).dialog("close");} + } + }); } function regenerateNames() { @@ -226,7 +215,7 @@ function editBurgs() { if (this.classList.contains("pressed")) {exitAddBurgMode(); return;}; customization = 3; this.classList.add("pressed"); - tip("Click on the map to create a new burg. Hold Shift to add multiple", true); + tip("Click on the map to create a new burg. Hold Shift to add multiple", true, "warn"); viewbox.style("cursor", "crosshair").on("click", addBurgOnClick); } diff --git a/modules/ui/diplomacy-editor.js b/modules/ui/diplomacy-editor.js index a74dddf4..7338ab2c 100644 --- a/modules/ui/diplomacy-editor.js +++ b/modules/ui/diplomacy-editor.js @@ -64,7 +64,7 @@ function editDiplomacy() { const tip = s.fullName + description[index] + selName; lines += `
-
${s.fullName}
+
${s.fullName}
`; diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 8abfdfcb..3f25fa5f 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -126,7 +126,8 @@ function addBurg(point) { const feature = cells.f[cell]; const population = Math.max((cells.s[cell] + cells.road[cell]) / 3 + i / 1000 + cell % 100 / 1000, .1); - pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: false, port: 0, population}); + + pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: 0, port: 0, population}); cells.burg[cell] = i; const townSize = burgIcons.select("#towns").attr("size") || 0.5; @@ -135,6 +136,7 @@ function addBurg(point) { burgLabels.select("#towns").append("text").attr("id", "burgLabel"+i).attr("data-id", i) .attr("x", x).attr("y", y).attr("dy", `${townSize * -1.5}px`).text(name); + BurgsAndStates.defineFeatures(pack.burgs[i]); return i; } @@ -173,6 +175,40 @@ function removeBurg(id) { pack.cells.burg[cell] = 0; } +function toggleCapital(burg) { + const state = pack.burgs[burg].state; + if (!state) {tip("Neutral lands cannot have a capital", false, "error"); return;} + if (pack.burgs[burg].capital) {tip("To change capital please assign a capital status to another burg of this state", false, "error"); return;} + const old = pack.states[state].capital; + + // change statuses + pack.states[state].capital = burg; + pack.states[state].center = pack.burgs[burg].cell; + pack.burgs[burg].capital = 1; + pack.burgs[old].capital = 0; + moveBurgToGroup(burg, "cities"); + moveBurgToGroup(old, "towns"); +} + +function togglePort(burg) { + const anchor = document.querySelector("#anchors [data-id='" + burg + "']"); + if (anchor) anchor.remove(); + const b = pack.burgs[burg]; + if (b.port) {b.port = 0; return;} // not a port anymore + + const haven = pack.cells.haven[b.cell]; + const port = haven ? pack.cells.f[haven] : -1; + if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, "warn"); + b.port = port; + + const g = b.capital ? "cities" : "towns"; + const group = anchors.select("g#"+g); + const size = +group.attr("size"); + group.append("use").attr("xlink:href", "#icon-anchor").attr("data-id", burg) + .attr("x", rn(b.x - size * .47, 2)).attr("y", rn(b.y - size * .47, 2)) + .attr("width", size).attr("height", size); +} + // draw legend box function drawLegend(name, data) { legend.selectAll("*").remove(); // fully redraw every time diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index c9fe62a5..bdb7a2fd 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -62,7 +62,7 @@ function editHeightmap() { } else if (type === "risk") { terrs.attr("mask", null); defs.selectAll("#land, #water").selectAll("path").remove(); - viewbox.selectAll("#coastline *, #lakes *, #oceanLayers path").remove(); + viewbox.selectAll("#coastline path, #lakes path, #oceanLayers path").remove(); changeOnlyLand.checked = false; } @@ -239,6 +239,16 @@ function getHeight(h) { c.y = p[1]; } + // recalculate zones to grid + zones.selectAll("g").each(function() { + const zone = d3.select(this); + const dataCells = zone.attr("data-cells"); + const cells = dataCells ? dataCells.split(",").map(i => +i) : []; + const g = cells.map(i => pack.cells.g[i]); + zone.attr("data-cells", g); + zone.selectAll("*").remove(); + }); + markFeatures(); OceanLayers(); calculateTemperatures(); @@ -324,6 +334,20 @@ function getHeight(h) { drawStates(); drawBorders(); + // restore zones from grid + zones.selectAll("g").each(function() { + const zone = d3.select(this); + const g = zone.attr("data-cells"); + const gCells = g ? g.split(",").map(i => +i) : []; + const cells = pack.cells.i.filter(i => gCells.includes(pack.cells.g[i])); + + zone.attr("data-cells", cells); + zone.selectAll("*").remove(); + const base = zone.attr("id") + "_"; // id generic part + zone.selectAll("*").data(cells).enter().append("polygon") + .attr("points", d => getPackPolygon(d)).attr("id", d => base + d); + }); + console.timeEnd("restoreRiskedData"); console.groupEnd("Edit Heightmap"); } diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index b800a5d3..6c313623 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -36,20 +36,17 @@ function editProvinces() { if (customization) return; const el = ev.target, cl = el.classList, line = el.parentNode, p = +line.dataset.id; if (cl.contains("zoneFill")) changeFill(el); else - if (cl.contains("icon-fleur")) provinceOpenCOA(p); else + if (cl.contains("name")) editProvinceName(p); else + if (cl.contains("icon-fleur")) provinceOpenCOA(ev, p); else if (cl.contains("icon-star-empty")) capitalZoomIn(p); else if (cl.contains("icon-flag-empty")) declareProvinceIndependence(p); else if (cl.contains("culturePopulation")) changePopulation(p); else if (cl.contains("icon-pin")) focusOn(p, cl); else if (cl.contains("icon-trash-empty")) removeProvince(p); - if (cl.contains("hoverButton") && cl.contains("stateName")) regenerateName(p, line); else - if (cl.contains("hoverButton") && cl.contains("stateForm")) regenerateForm(p, line); }); body.addEventListener("input", function(ev) { const el = ev.target, cl = el.classList, line = el.parentNode, p = +line.dataset.id; - if (cl.contains("stateName")) changeName(p, line, el.value); else - if (cl.contains("stateForm")) changeForm(p, line, el.value); else if (cl.contains("cultureBase")) changeCapital(p, line, el.value); }); @@ -62,7 +59,7 @@ function editProvinces() { function collectStatistics() { const cells = pack.cells, provinces = pack.provinces; provinces.forEach(p => { - if (!p.i) return; + if (!p.i || p.removed) return; p.area = p.rural = p.urban = 0; p.burgs = []; }); @@ -77,6 +74,11 @@ function editProvinces() { provinces[p].urban += pack.burgs[cells.burg[i]].population; provinces[p].burgs.push(cells.burg[i]); } + + provinces.forEach(p => { + if (!p.i || p.removed) return; + if (!p.burg && p.burgs.length) p.burg = p.burgs[0]; + }); } function updateFilter() { @@ -112,11 +114,9 @@ function editProvinces() { const focused = defs.select("#fog #focusProvince"+p.i).size(); lines += `
- - - - - + + + @@ -156,8 +156,6 @@ function editProvinces() { } function provinceHighlightOn(event) { - if (!customization) event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.remove("placeholder")); - const province = +event.target.dataset.id; const el = body.querySelector(`div[data-id='${province}']`); if (el) el.classList.add("active"); @@ -169,8 +167,6 @@ function editProvinces() { } function provinceHighlightOff(event) { - if (!customization) event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.add("placeholder")); - const province = +event.target.dataset.id; const el = body.querySelector(`div[data-id='${province}']`); if (el) el.classList.remove("active"); @@ -194,9 +190,17 @@ function editProvinces() { openPicker(currentFill, callback); } - function provinceOpenCOA(p) { - const url = `https://ironarachne.com/heraldry/${seed}-p${p}`; - window.open(url, '_blank'); + function provinceOpenCOA(event, p) { + const defSeed = `${seed}-p${p}`; + + if (event.ctrlKey) { + 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); } function capitalZoomIn(p) { @@ -211,16 +215,18 @@ function editProvinces() { const oldState = pack.provinces[p].state; const newState = pack.states.length; - // turn burg into a capital + // turn province burg into a capital const burg = provinces[p].burg; if (!burg) return; - pack.burgs[burg].capital = true; - pack.burgs[burg].state = newState; + pack.burgs[burg].capital = 1; moveBurgToGroup(burg, "cities"); + // move all burgs to a new state + provinces[p].burgs.forEach(b => pack.burgs[b].state = newState); + // difine new state attributes - const center = provinces[p].center; - const culture = cells.culture[center]; + const center = pack.burgs[burg].cell; + const culture = pack.burgs[burg].culture; const name = provinces[p].name; const color = getRandomColor(); @@ -358,28 +364,69 @@ function editProvinces() { refreshProvincesEditor(); } - function changeName(p, line, value) { - pack.provinces[p].name = line.querySelector(".stateName").value = line.dataset.name = value; - pack.provinces[p].fullName = value + " " + pack.provinces[p].formName; - provs.select("#provinceLabel"+p).text(value); - } + function editProvinceName(province) { + const p = pack.provinces[province]; + document.getElementById("provinceNameEditor").dataset.province = province; + document.getElementById("provinceNameEditorShort").value = p.name; + applyOption(provinceNameEditorSelectForm, p.formName) + document.getElementById("provinceNameEditorFull").value = p.fullName; - function regenerateName(p, line) { - const c = pack.cells.culture[pack.provinces[p].center]; - const name = Names.getState(Names.getCultureShort(c), c); - changeName(p, line, name); - } + $("#provinceNameEditor").dialog({ + resizable: false, title: "Change province name", width: "22em", buttons: { + Apply: function() {applyNameChange(p); $(this).dialog("close");}, + Cancel: function() {$(this).dialog("close");} + }, position: {my: "center", at: "center", of: "svg"} + }); - function changeForm(p, line, value) { - pack.provinces[p].formName = line.querySelector(".stateForm").value = line.dataset.form = value; - pack.provinces[p].fullName = pack.provinces[p].name + " " + value; - } + if (modules.editProvinceName) return; + modules.editProvinceName = true; - function regenerateForm(p, line) { - const forms = ["County", "Earldom", "Shire", "Landgrave", 'Margrave', "Barony", "Province", - "Department", "Governorate", "State", "Canton", "Prefecture", "Parish", "Deanery", - "Council", "District", "Republic", "Territory", "Land", "Region"]; - changeForm(p, line, ra(forms)); + // add listeners + document.getElementById("provinceNameEditorShortCulture").addEventListener("click", regenerateShortNameCuture); + document.getElementById("provinceNameEditorShortRandom").addEventListener("click", regenerateShortNameRandom); + document.getElementById("provinceNameEditorAddForm").addEventListener("click", addCustomForm); + document.getElementById("provinceNameEditorFullRegenerate").addEventListener("click", regenerateFullName); + + function regenerateShortNameCuture() { + const province = +provinceNameEditor.dataset.province; + const culture = pack.cells.culture[pack.provinces[province].center]; + const name = Names.getState(Names.getCultureShort(culture), culture); + document.getElementById("provinceNameEditorShort").value = name; + } + + function regenerateShortNameRandom() { + const base = rand(nameBase.length-1); + const name = Names.getState(Names.getBase(base), undefined, base); + document.getElementById("provinceNameEditorShort").value = name; + } + + function addCustomForm() { + const value = provinceNameEditorCustomForm.value; + const displayed = provinceNameEditorCustomForm.style.display === "inline-block"; + provinceNameEditorCustomForm.style.display = displayed ? "none" : "inline-block"; + provinceNameEditorSelectForm.style.display = displayed ? "inline-block" : "none"; + if (displayed && value) applyOption(provinceNameEditorSelectForm, value); + } + + function regenerateFullName() { + const short = document.getElementById("provinceNameEditorShort").value; + const form = document.getElementById("provinceNameEditorSelectForm").value; + document.getElementById("provinceNameEditorFull").value = getFullName(); + + function getFullName() { + if (!form) return short; + if (!short && form) return "The " + form; + return short + " " + form; + } + } + + function applyNameChange(p) { + p.name = document.getElementById("provinceNameEditorShort").value; + p.formName = document.getElementById("provinceNameEditorSelectForm").value; + p.fullName = document.getElementById("provinceNameEditorFull").value; + provs.select("#provinceLabel"+p.i).text(p.name); + refreshProvincesEditor(); + } } function changeCapital(p, line, value) { diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index 3a647071..8cfe82db 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -41,19 +41,16 @@ function editStates() { body.addEventListener("click", function(ev) { const el = ev.target, cl = el.classList, line = el.parentNode, state = +line.dataset.id; if (cl.contains("zoneFill")) stateChangeFill(el); else - if (cl.contains("icon-fleur")) stateOpenCOA(state); else + if (cl.contains("name")) editStateName(state); else + if (cl.contains("icon-fleur")) stateOpenCOA(ev, state); else if (cl.contains("icon-star-empty")) stateCapitalZoomIn(state); else if (cl.contains("culturePopulation")) changePopulation(state); else if (cl.contains("icon-pin")) focusOnState(state, cl); else - if (cl.contains("icon-trash-empty")) stateRemove(state); else - if (cl.contains("hoverButton") && cl.contains("stateName")) regenerateName(state, line); else - if (cl.contains("hoverButton") && cl.contains("stateForm")) regenerateForm(state, line); + if (cl.contains("icon-trash-empty")) stateRemove(state); }); body.addEventListener("input", function(ev) { const el = ev.target, cl = el.classList, line = el.parentNode, state = +line.dataset.id; - if (cl.contains("stateName")) stateChangeName(state, line, el.value); else - if (cl.contains("stateForm")) stateChangeForm(state, line, el.value); else if (cl.contains("stateCapital")) stateChangeCapitalName(state, line, el.value); else if (cl.contains("cultureType")) stateChangeType(state, line, el.value); else if (cl.contains("stateCulture")) stateChangeCulture(state, line, el.value); else @@ -88,7 +85,7 @@ function editStates() { lines += `
- + @@ -96,8 +93,8 @@ function editStates() {
${s.burgs}
- -
${si(area) + unit}
+ +
${si(area) + unit}
${si(population)}
@@ -111,12 +108,10 @@ function editStates() { const capital = pack.burgs[s.capital].name; lines += `
- - - - - - + + + + @@ -171,7 +166,6 @@ function editStates() { } function stateHighlightOn(event) { - if (!customization) event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.remove("placeholder")); if (!layerIsOn("toggleStates")) return; const state = +event.target.dataset.id; if (customization || !state) return; @@ -197,7 +191,6 @@ function editStates() { } function stateHighlightOff() { - event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.add("placeholder")); debug.selectAll(".highlight").each(function(el) { d3.select(this).call(removePath); }); @@ -219,63 +212,71 @@ function editStates() { openPicker(currentFill, callback); } - function stateChangeName(state, line, value) { - const oldName = pack.states[state].name; - pack.states[state].name = line.dataset.name = value; - pack.states[state].fullName = BurgsAndStates.getFullName(pack.states[state]); - changeLabel(state, oldName, value); - } + function editStateName(state) { + const s = pack.states[state]; + document.getElementById("stateNameEditor").dataset.state = state; + document.getElementById("stateNameEditorShort").value = s.name || ""; + applyOption(stateNameEditorSelectForm, s.formName); + document.getElementById("stateNameEditorFull").value = s.fullName || ""; - function regenerateName(state, line) { - const culture = pack.states[state].culture; - const oldName = pack.states[state].name; - const newName = Names.getState(Names.getCultureShort(culture), culture); - pack.states[state].name = line.dataset.name = line.querySelector(".stateName").value = newName; - pack.states[state].fullName = BurgsAndStates.getFullName(pack.states[state]); - changeLabel(state, oldName, newName); - } + $("#stateNameEditor").dialog({ + resizable: false, title: "Change state name", width: "22em", buttons: { + Apply: function() {applyNameChange(s); $(this).dialog("close");}, + Cancel: function() {$(this).dialog("close");} + }, position: {my: "center", at: "center", of: "svg"} + }); - function stateChangeForm(state, line, value) { - const oldForm = pack.states[state].formName; - pack.states[state].formName = line.dataset.form = value; - pack.states[state].fullName = BurgsAndStates.getFullName(pack.states[state]); - changeLabel(state, oldForm, value, true); - } + if (modules.editStateName) return; + modules.editStateName = true; - function regenerateForm(state, line) { - const oldForm = pack.states[state].formName; - let newForm = oldForm; + // add listeners + document.getElementById("stateNameEditorShortCulture").addEventListener("click", regenerateShortNameCuture); + document.getElementById("stateNameEditorShortRandom").addEventListener("click", regenerateShortNameRandom); + document.getElementById("stateNameEditorAddForm").addEventListener("click", addCustomForm); + document.getElementById("stateNameEditorFullRegenerate").addEventListener("click", regenerateFullName); - for (let i=0; newForm === oldForm && i < 50; i++) { - BurgsAndStates.defineStateForms([state]); - newForm = pack.states[state].formName; + function regenerateShortNameCuture() { + const state = +stateNameEditor.dataset.state; + const culture = pack.states[state].culture; + const name = Names.getState(Names.getCultureShort(culture), culture); + document.getElementById("stateNameEditorShort").value = name; } - line.dataset.form = line.querySelector(".stateForm").value = newForm; - changeLabel(state, oldForm, newForm, true); - } - - function changeLabel(state, oldName, newName, form) { - const label = document.getElementById("stateLabel"+state); - if (!label) return; - - const tspan = Array.from(label.querySelectorAll('tspan')); - const tspanAdj = !form && oldName && newName && pack.states[state].formName ? tspan.find(el => el.textContent.includes(getAdjective(oldName))) : null; - const tspanName = tspanAdj || !oldName || !newName ? null : tspan.find(el => el.textContent.includes(oldName)); - - if (tspanAdj) { - tspanAdj.textContent = tspanAdj.textContent.replace(getAdjective(oldName), getAdjective(newName)); - const l = tspanAdj.getComputedTextLength(); - tspanAdj.setAttribute("x", l / -2); - } if (tspanName) { - tspanName.textContent = tspanName.textContent.replace(oldName, newName); - const l = tspanName.getComputedTextLength(); - tspanName.setAttribute("x", l / -2); - } else { - BurgsAndStates.drawStateLabels([state]); + function regenerateShortNameRandom() { + const base = rand(nameBase.length-1); + const name = Names.getState(Names.getBase(base), undefined, base); + document.getElementById("stateNameEditorShort").value = name; } - tip("State label is automatically changed. To make a custom change click on a label and edit the text there", false, "warn"); + function addCustomForm() { + const value = stateNameEditorCustomForm.value; + const displayed = stateNameEditorCustomForm.style.display === "inline-block"; + stateNameEditorCustomForm.style.display = displayed ? "none" : "inline-block"; + stateNameEditorSelectForm.style.display = displayed ? "inline-block" : "none"; + if (displayed && value) applyOption(stateNameEditorSelectForm, value); + } + + function regenerateFullName() { + const short = document.getElementById("stateNameEditorShort").value; + const form = document.getElementById("stateNameEditorSelectForm").value; + document.getElementById("stateNameEditorFull").value = getFullName(); + + function getFullName() { + if (!form) return short; + if (!short && form) return "The " + form; + const tick = +stateNameEditorFullRegenerate.dataset.tick; + stateNameEditorFullRegenerate.dataset.tick = tick+1; + return tick%2 ? getAdjective(short) + " " + form : form + " of " + short; + } + } + + function applyNameChange(s) { + s.name = document.getElementById("stateNameEditorShort").value; + s.formName = document.getElementById("stateNameEditorSelectForm").value; + s.fullName = document.getElementById("stateNameEditorFull").value; + if (stateNameEditorUpdateLabel.checked) BurgsAndStates.drawStateLabels([s.i]); + refreshStatesEditor(); + } } function stateChangeCapitalName(state, line, value) { @@ -286,9 +287,17 @@ function editStates() { document.querySelector("#burgLabel"+capital).textContent = value; } - function stateOpenCOA(state) { - const url = `https://ironarachne.com/heraldry/${seed}-s${state}`; - window.open(url, '_blank'); + function stateOpenCOA(event, state) { + const defSeed = `${seed}-s${state}`; + + if (event.ctrlKey) { + 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); } function changePopulation(state) { @@ -413,7 +422,7 @@ function editStates() { }); const capital = pack.states[state].capital; - pack.burgs[capital].capital = false; + pack.burgs[capital].capital = 0; pack.burgs[capital].state = 0; moveBurgToGroup(capital, "towns"); @@ -788,7 +797,7 @@ function editStates() { const newState = states.length; // turn burg into a capital - burgs[burg].capital = true; + burgs[burg].capital = 1; burgs[burg].state = newState; moveBurgToGroup(burg, "cities"); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 08e47593..f57fb1ed 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -15,7 +15,7 @@ toolsContent.addEventListener("click", function(event) { if (button === "editCulturesButton") editCultures(); else if (button === "editReligions") editReligions(); else if (button === "editNamesBaseButton") editNamesbase(); else - if (button === "editBurgsButton") editBurgs(); else + if (button === "overviewBurgsButton") editBurgs(); else if (button === "editUnitsButton") editUnits(); else if (button === "editNotesButton") editNotes(); else if (button === "editZonesButton") editZones(); @@ -122,7 +122,7 @@ function regenerateBurgs() { const burg = addBurg([cells.p[s.center][0], cells.p[s.center][1]]); // add new burg s.capital = burg; s.center = pack.burgs[burg].cell; - pack.burgs[burg].capital = true; + pack.burgs[burg].capital = 1; pack.burgs[burg].state = s.i; moveBurgToGroup(burg, "cities"); }); @@ -153,7 +153,7 @@ function regenerateStates() { // turn all old capitals into towns burgs.filter(b => b.capital).forEach(b => { moveBurgToGroup(b.i, "towns"); - b.capital = false; + b.capital = 0; }); const neutral = pack.states[0].name; @@ -171,7 +171,7 @@ function regenerateStates() { } capitalsTree.add([x, y]); - capital.capital = true; + capital.capital = 1; moveBurgToGroup(capital.i, "cities"); const culture = capital.culture; diff --git a/modules/ui/zones-editor.js b/modules/ui/zones-editor.js index a38d13b2..663c25fb 100644 --- a/modules/ui/zones-editor.js +++ b/modules/ui/zones-editor.js @@ -211,7 +211,8 @@ function editZones() { zone.attr("data-cells", cells); zone.selectAll("*").remove(); const base = zone.attr("id") + "_"; // id generic part - zone.selectAll("*").data(cells).enter().append("polygon").attr("points", d => getPackPolygon(d)).attr("id", d => base + d); + zone.selectAll("*").data(cells).enter().append("polygon") + .attr("points", d => getPackPolygon(d)).attr("id", d => base + d); }); exitZonesManualAssignment(); diff --git a/modules/utils.js b/modules/utils.js index 6095f7ac..95cd1935 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -537,6 +537,11 @@ function parseError(error) { return errorParsed; } +// open URL in a new tab or window +function openURL(url) { + window.open(url, '_blank'); +} + // polyfills if (Array.prototype.flat === undefined) { Array.prototype.flat = function() {