mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
buttons to release all provinces and regenerate culture name
This commit is contained in:
parent
567cf3676a
commit
6de70f5897
8 changed files with 301 additions and 149 deletions
|
|
@ -1411,11 +1411,16 @@ div.states > .statePopulation {
|
|||
width: 3em;
|
||||
}
|
||||
|
||||
div.states:hover > .hiddenIcon {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
div.states .icon-pencil,
|
||||
div.states .icon-trash-empty,
|
||||
div.states .icon-eye,
|
||||
div.states .icon-pin,
|
||||
div.states .icon-flag-empty {
|
||||
div.states .icon-flag-empty,
|
||||
div.states .icon-cw {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
|
|||
15
index.html
15
index.html
|
|
@ -2708,6 +2708,7 @@
|
|||
<button id="provincesManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
|
||||
</div>
|
||||
|
||||
<button id="provincesRelease" data-tip="Release all provinces. It will make all provinces with burgs independent" class="icon-flag"></button>
|
||||
<button id="provincesAdd" data-tip="Add a new province. Hold Shift to add multiple" class="icon-plus"></button>
|
||||
<button id="provincesRemoveAll" data-tip="Remove all provinces. States will remain as they are" class="icon-trash"></button>
|
||||
|
||||
|
|
@ -2806,13 +2807,13 @@
|
|||
<div id="culturesEditor" class="dialog stable" style="display: none">
|
||||
<div id="culturesHeader" class="header">
|
||||
<div style="left:1.8em" data-tip="Click to sort by culture name" class="sortable alphabetically" data-sortby="name">Culture </div>
|
||||
<div style="left:8.7em" data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells </div>
|
||||
<div style="left:13.2em" data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expan. </div>
|
||||
<div style="left:18.6em" data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type </div>
|
||||
<div style="left:24.9em" data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area </div>
|
||||
<div style="left:28.8em" data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population </div>
|
||||
<div style="left:35.8em" data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase </div>
|
||||
<div style="left:42.9em" data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems </div>
|
||||
<div style="left:9.8em" data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells </div>
|
||||
<div style="left:14.3em" data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expan. </div>
|
||||
<div style="left:19.7em" data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type </div>
|
||||
<div style="left:26em" data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area </div>
|
||||
<div style="left:29.9em" data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population </div>
|
||||
<div style="left:36.9em" data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase </div>
|
||||
<div style="left:44em" data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems </div>
|
||||
</div>
|
||||
<div id="culturesBody" class="table" data-type="absolute"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -679,8 +679,8 @@ window.BurgsAndStates = (function () {
|
|||
// calculate states data like area, population etc.
|
||||
const collectStatistics = function () {
|
||||
TIME && console.time("collectStatistics");
|
||||
const cells = pack.cells,
|
||||
states = pack.states;
|
||||
const {cells, states} = pack;
|
||||
|
||||
states.forEach(s => {
|
||||
if (s.removed) return;
|
||||
s.cells = s.area = s.burgs = s.rural = s.urban = 0;
|
||||
|
|
|
|||
|
|
@ -128,20 +128,14 @@ window.Names = (function () {
|
|||
|
||||
// generate name for culture
|
||||
const getCulture = function (culture, min, max, dupl) {
|
||||
if (culture === undefined) {
|
||||
ERROR && console.error("Please define a culture");
|
||||
return;
|
||||
}
|
||||
if (culture === undefined) return ERROR && console.error("Please define a culture");
|
||||
const base = pack.cultures[culture].base;
|
||||
return getBase(base, min, max, dupl);
|
||||
};
|
||||
|
||||
// generate short name for culture
|
||||
const getCultureShort = function (culture) {
|
||||
if (culture === undefined) {
|
||||
ERROR && console.error("Please define a culture");
|
||||
return;
|
||||
}
|
||||
if (culture === undefined) return ERROR && console.error("Please define a culture");
|
||||
return getBaseShort(pack.cultures[culture].base);
|
||||
};
|
||||
|
||||
|
|
@ -157,55 +151,75 @@ window.Names = (function () {
|
|||
};
|
||||
|
||||
// generate state name based on capital or random name and culture-specific suffix
|
||||
// prettier-ignore
|
||||
const getState = function(name, culture, base) {
|
||||
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;}
|
||||
const getState = function (name, culture, base) {
|
||||
if (name === undefined) return ERROR && console.error("Please define a base name");
|
||||
if (culture === undefined && base === undefined) return ERROR && console.error("Please define a culture");
|
||||
if (base === undefined) base = pack.cultures[culture].base;
|
||||
|
||||
// exclude endings inappropriate for states name
|
||||
if (name.includes(" ")) name = capitalize(name.replace(/ /g, "").toLowerCase()); // don't allow multiword state names
|
||||
if (name.length > 6 && name.slice(-4) === "berg") name = name.slice(0,-4); // remove -berg for any
|
||||
if (name.length > 5 && name.slice(-3) === "ton") name = name.slice(0,-3); // remove -ton for any
|
||||
if (name.length > 6 && name.slice(-4) === "berg") name = name.slice(0, -4); // remove -berg for any
|
||||
if (name.length > 5 && name.slice(-3) === "ton") name = name.slice(0, -3); // remove -ton for any
|
||||
|
||||
if (base === 5 && ["sk", "ev", "ov"].includes(name.slice(-2))) name = name.slice(0,-2); // remove -sk/-ev/-ov for Ruthenian
|
||||
else if (base === 12) return vowel(name.slice(-1)) ? name : name + "u"; // Japanese ends on any vowel or -u
|
||||
else if (base === 18 && P(.4)) name = vowel(name.slice(0,1).toLowerCase()) ? "Al" + name.toLowerCase() : "Al " + name; // Arabic starts with -Al
|
||||
if (base === 5 && ["sk", "ev", "ov"].includes(name.slice(-2))) name = name.slice(0, -2);
|
||||
// remove -sk/-ev/-ov for Ruthenian
|
||||
else if (base === 12) return vowel(name.slice(-1)) ? name : name + "u";
|
||||
// Japanese ends on any vowel or -u
|
||||
else if (base === 18 && P(0.4)) name = vowel(name.slice(0, 1).toLowerCase()) ? "Al" + name.toLowerCase() : "Al " + name; // Arabic starts with -Al
|
||||
|
||||
// no suffix for fantasy bases
|
||||
if (base > 32 && base < 42) return name;
|
||||
|
||||
// define if suffix should be used
|
||||
if (name.length > 3 && vowel(name.slice(-1))) {
|
||||
if (vowel(name.slice(-2,-1)) && P(.85)) name = name.slice(0,-2); // 85% for vv
|
||||
else if (P(.7)) name = name.slice(0,-1); // ~60% for cv
|
||||
if (vowel(name.slice(-2, -1)) && P(0.85)) name = name.slice(0, -2);
|
||||
// 85% for vv
|
||||
else if (P(0.7)) name = name.slice(0, -1);
|
||||
// ~60% for cv
|
||||
else return name;
|
||||
} else if (P(.4)) return name; // 60% for cc and vc
|
||||
} else if (P(0.4)) return name; // 60% for cc and vc
|
||||
|
||||
// define suffix
|
||||
let suffix = "ia"; // standard suffix
|
||||
|
||||
const rnd = Math.random(), l = name.length;
|
||||
if (base === 3 && rnd < .03 && l < 7) suffix = "terra"; // Italian
|
||||
else if (base === 4 && rnd < .03 && l < 7) suffix = "terra"; // Spanish
|
||||
else if (base === 13 && rnd < .03 && l < 7) suffix = "terra"; // Portuguese
|
||||
else if (base === 2 && rnd < .03 && l < 7) suffix = "terre"; // French
|
||||
else if (base === 0 && rnd < .5 && l < 7) suffix = "land"; // German
|
||||
else if (base === 1 && rnd < .4 && l < 7 ) suffix = "land"; // English
|
||||
else if (base === 6 && rnd < .3 && l < 7) suffix = "land"; // Nordic
|
||||
else if (base === 32 && rnd < .1 && l < 7) suffix = "land"; // generic Human
|
||||
else if (base === 7 && rnd < .1) suffix = "eia"; // Greek
|
||||
else if (base === 9 && rnd < .35) suffix = "maa"; // Finnic
|
||||
else if (base === 15 && rnd < .4 && l < 6) suffix = "orszag"; // Hungarian
|
||||
else if (base === 16) suffix = rnd < .6 ? "stan" : "ya"; // Turkish
|
||||
else if (base === 10) suffix = "guk"; // Korean
|
||||
else if (base === 11) suffix = " Guo"; // Chinese
|
||||
else if (base === 14) suffix = rnd < .5 && l < 6 ? "tlan" : "co"; // Nahuatl
|
||||
else if (base === 17 && rnd < .8) suffix = "a"; // Berber
|
||||
else if (base === 18 && rnd < .8) suffix = "a"; // Arabic
|
||||
const rnd = Math.random(),
|
||||
l = name.length;
|
||||
if (base === 3 && rnd < 0.03 && l < 7) suffix = "terra";
|
||||
// Italian
|
||||
else if (base === 4 && rnd < 0.03 && l < 7) suffix = "terra";
|
||||
// Spanish
|
||||
else if (base === 13 && rnd < 0.03 && l < 7) suffix = "terra";
|
||||
// Portuguese
|
||||
else if (base === 2 && rnd < 0.03 && l < 7) suffix = "terre";
|
||||
// French
|
||||
else if (base === 0 && rnd < 0.5 && l < 7) suffix = "land";
|
||||
// German
|
||||
else if (base === 1 && rnd < 0.4 && l < 7) suffix = "land";
|
||||
// English
|
||||
else if (base === 6 && rnd < 0.3 && l < 7) suffix = "land";
|
||||
// Nordic
|
||||
else if (base === 32 && rnd < 0.1 && l < 7) suffix = "land";
|
||||
// generic Human
|
||||
else if (base === 7 && rnd < 0.1) suffix = "eia";
|
||||
// Greek
|
||||
else if (base === 9 && rnd < 0.35) suffix = "maa";
|
||||
// Finnic
|
||||
else if (base === 15 && rnd < 0.4 && l < 6) suffix = "orszag";
|
||||
// Hungarian
|
||||
else if (base === 16) suffix = rnd < 0.6 ? "stan" : "ya";
|
||||
// Turkish
|
||||
else if (base === 10) suffix = "guk";
|
||||
// Korean
|
||||
else if (base === 11) suffix = " Guo";
|
||||
// Chinese
|
||||
else if (base === 14) suffix = rnd < 0.5 && l < 6 ? "tlan" : "co";
|
||||
// Nahuatl
|
||||
else if (base === 17 && rnd < 0.8) suffix = "a";
|
||||
// Berber
|
||||
else if (base === 18 && rnd < 0.8) suffix = "a"; // Arabic
|
||||
|
||||
return validateSuffix(name, suffix);
|
||||
}
|
||||
};
|
||||
|
||||
function validateSuffix(name, suffix) {
|
||||
if (name.slice(-1 * suffix.length) === suffix) return name; // no suffix if name already ends with it
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ function editCultures() {
|
|||
// add line for each culture
|
||||
function culturesEditorAddLines() {
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
let lines = "",
|
||||
totalArea = 0,
|
||||
totalPopulation = 0;
|
||||
let lines = "";
|
||||
let totalArea = 0;
|
||||
let totalPopulation = 0;
|
||||
|
||||
const emblemShapeGroup = document.getElementById("emblemShape").selectedOptions[0].parentNode.label;
|
||||
const selectShape = emblemShapeGroup === "Diversiform";
|
||||
|
|
@ -84,7 +84,8 @@ function editCultures() {
|
|||
lines += `<div class="states" data-id=${c.i} data-name="${c.name}" data-color="" data-cells=${c.cells}
|
||||
data-area=${area} data-population=${population} data-base=${c.base} data-type="" data-expansionism="" data-emblems="${c.shield}">
|
||||
<svg width="9" height="9" class="placeholder"></svg>
|
||||
<input data-tip="Culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Neutral culture name. Click and type to change" class="cultureName italic" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<span class="icon-cw placeholder"></span>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
|
||||
<span class="icon-resize-full placeholder hide"></span>
|
||||
|
|
@ -96,19 +97,28 @@ function editCultures() {
|
|||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
|
||||
${selectShape ? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>` : ""}
|
||||
${
|
||||
selectShape
|
||||
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
|
||||
: ""
|
||||
}
|
||||
</div>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
lines += `<div class="states cultures" data-id=${c.i} data-name="${c.name}" data-color="${c.color}" data-cells=${c.cells}
|
||||
data-area=${area} data-population=${population} data-base=${c.base} data-type=${c.type} data-expansionism=${c.expansionism} data-emblems="${c.shield}">
|
||||
<svg data-tip="Culture fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${c.color}" class="fillRect pointer"></svg>
|
||||
<svg data-tip="Culture fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px">
|
||||
<rect x="0" y="0" width="100%" height="100%" fill="${c.color}" class="fillRect pointer">
|
||||
</svg>
|
||||
<input data-tip="Culture name. Click and type to change" class="cultureName" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Regenerate culture name" class="icon-cw hiddenIcon" style="visibility: hidden"></span>
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
|
||||
<span data-tip="Culture expansionism. Defines competitive size" class="icon-resize-full hide"></span>
|
||||
<input data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${c.expansionism}>
|
||||
<input data-tip="Culture expansionism. Defines competitive size. Click to change, then click Recalculate to apply change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${
|
||||
c.expansionism
|
||||
}>
|
||||
<select data-tip="Culture type. Defines growth model. Click to change" class="cultureType">${getTypeOptions(c.type)}</select>
|
||||
<span data-tip="Culture area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Culture area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
|
|
@ -116,7 +126,11 @@ function editCultures() {
|
|||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
||||
<select data-tip="Culture namesbase. Click to change. Click on arrows to re-generate names" class="cultureBase">${getBaseOptions(c.base)}</select>
|
||||
${selectShape ? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>` : ""}
|
||||
${
|
||||
selectShape
|
||||
? `<select data-tip="Emblem shape associated with culture. Click to change" class="cultureShape hide">${getShapeOptions(c.shield)}</select>`
|
||||
: ""
|
||||
}
|
||||
<span data-tip="Remove culture" class="icon-trash-empty hide"></span>
|
||||
</div>`;
|
||||
}
|
||||
|
|
@ -136,6 +150,7 @@ function editCultures() {
|
|||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectCultureOnLineClick));
|
||||
body.querySelectorAll("rect.fillRect").forEach(el => el.addEventListener("click", cultureChangeColor));
|
||||
body.querySelectorAll("div > input.cultureName").forEach(el => el.addEventListener("input", cultureChangeName));
|
||||
body.querySelectorAll("div > span.icon-cw").forEach(el => el.addEventListener("click", cultureRegenerateName));
|
||||
body.querySelectorAll("div > input.statePower").forEach(el => el.addEventListener("input", cultureChangeExpansionism));
|
||||
body.querySelectorAll("div > select.cultureType").forEach(el => el.addEventListener("change", cultureChangeType));
|
||||
body.querySelectorAll("div > select.cultureBase").forEach(el => el.addEventListener("change", cultureChangeBase));
|
||||
|
|
@ -258,6 +273,13 @@ function editCultures() {
|
|||
);
|
||||
}
|
||||
|
||||
function cultureRegenerateName() {
|
||||
const culture = +this.parentNode.dataset.id;
|
||||
const name = Names.getCultureShort(culture);
|
||||
this.parentNode.querySelector("input.cultureName").value = name;
|
||||
pack.cultures[culture].name = name;
|
||||
}
|
||||
|
||||
function cultureChangeExpansionism() {
|
||||
const culture = +this.parentNode.dataset.id;
|
||||
this.parentNode.dataset.expansionism = this.value;
|
||||
|
|
@ -526,7 +548,13 @@ function editCultures() {
|
|||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = "<div id='cultureInfo' class='chartInfo'>‍</div>";
|
||||
const svg = d3.select("#alertMessage").insert("svg", "#cultureInfo").attr("id", "hierarchy").attr("width", width).attr("height", height).style("text-anchor", "middle");
|
||||
const svg = d3
|
||||
.select("#alertMessage")
|
||||
.insert("svg", "#cultureInfo")
|
||||
.attr("id", "hierarchy")
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
.style("text-anchor", "middle");
|
||||
const graph = svg.append("g").attr("transform", `translate(10, -45)`);
|
||||
const links = graph.append("g").attr("fill", "none").attr("stroke", "#aaaaaa");
|
||||
const nodes = graph.append("g");
|
||||
|
|
@ -540,7 +568,24 @@ function editCultures() {
|
|||
.enter()
|
||||
.append("path")
|
||||
.attr("d", d => {
|
||||
return "M" + d.source.x + "," + d.source.y + "C" + d.source.x + "," + (d.source.y * 3 + d.target.y) / 4 + " " + d.target.x + "," + (d.source.y * 2 + d.target.y) / 3 + " " + d.target.x + "," + d.target.y;
|
||||
return (
|
||||
"M" +
|
||||
d.source.x +
|
||||
"," +
|
||||
d.source.y +
|
||||
"C" +
|
||||
d.source.x +
|
||||
"," +
|
||||
(d.source.y * 3 + d.target.y) / 4 +
|
||||
" " +
|
||||
d.target.x +
|
||||
"," +
|
||||
(d.source.y * 2 + d.target.y) / 3 +
|
||||
" " +
|
||||
d.target.x +
|
||||
"," +
|
||||
d.target.y
|
||||
);
|
||||
});
|
||||
|
||||
const node = nodes
|
||||
|
|
@ -661,7 +706,11 @@ function editCultures() {
|
|||
$("#culturesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}});
|
||||
|
||||
tip("Click on culture to select, drag the circle to change culture", true);
|
||||
viewbox.style("cursor", "crosshair").on("click", selectCultureOnMapClick).call(d3.drag().on("start", dragCultureBrush)).on("touchmove mousemove", moveCultureBrush);
|
||||
viewbox
|
||||
.style("cursor", "crosshair")
|
||||
.on("click", selectCultureOnMapClick)
|
||||
.call(d3.drag().on("start", dragCultureBrush))
|
||||
.on("touchmove mousemove", moveCultureBrush);
|
||||
|
||||
body.querySelector("div").classList.add("selected");
|
||||
}
|
||||
|
|
@ -712,7 +761,14 @@ function editCultures() {
|
|||
|
||||
// change of append new element
|
||||
if (exists.size()) exists.attr("data-culture", cultureNew).attr("fill", color).attr("stroke", color);
|
||||
else temp.append("polygon").attr("data-cell", i).attr("data-culture", cultureNew).attr("points", getPackPolygon(i)).attr("fill", color).attr("stroke", color);
|
||||
else
|
||||
temp
|
||||
.append("polygon")
|
||||
.attr("data-cell", i)
|
||||
.attr("data-culture", cultureNew)
|
||||
.attr("points", getPackPolygon(i))
|
||||
.attr("fill", color)
|
||||
.attr("stroke", color);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ function editProvinces() {
|
|||
document.getElementById("provincesManually").addEventListener("click", enterProvincesManualAssignent);
|
||||
document.getElementById("provincesManuallyApply").addEventListener("click", applyProvincesManualAssignent);
|
||||
document.getElementById("provincesManuallyCancel").addEventListener("click", () => exitProvincesManualAssignment());
|
||||
document.getElementById("provincesRelease").addEventListener("click", triggerProvincesRelease);
|
||||
document.getElementById("provincesAdd").addEventListener("click", enterAddProvinceMode);
|
||||
document.getElementById("provincesRecolor").addEventListener("click", recolorProvinces);
|
||||
|
||||
|
|
@ -129,19 +130,27 @@ function editProvinces() {
|
|||
const separable = p.burg && p.burg !== pack.states[p.state].capital;
|
||||
const focused = defs.select("#fog #focusProvince" + p.i).size();
|
||||
COArenderer.trigger("provinceCOA" + p.i, p.coa);
|
||||
lines += `<div class="states" data-id=${p.i} data-name="${p.name}" data-form="${p.formName}" data-color="${p.color}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
|
||||
<svg data-tip="Province fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${p.color}" class="fillRect pointer"></svg>
|
||||
lines += `<div class="states" data-id=${p.i} data-name="${p.name}" data-form="${p.formName}" data-color="${
|
||||
p.color
|
||||
}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
|
||||
<svg data-tip="Province fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${
|
||||
p.color
|
||||
}" class="fillRect pointer"></svg>
|
||||
<input data-tip="Province name. Click to change" class="name pointer" value="${p.name}" readonly>
|
||||
<svg data-tip="Click to show and edit province emblem" class="coaIcon hide" viewBox="0 0 200 200"><use href="#provinceCOA${p.i}"></use></svg>
|
||||
<input data-tip="Province form name. Click to change" class="name pointer hide" value="${p.formName}" readonly>
|
||||
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg ? "" : "placeholder"}"></span>
|
||||
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${p.burgs.length ? "" : "placeholder"}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}</select>
|
||||
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${
|
||||
p.burgs.length ? "" : "placeholder"
|
||||
}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""}</select>
|
||||
<input data-tip="Province owner" class="provinceOwner" value="${stateName}" disabled">
|
||||
<span data-tip="Province area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Province area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Declare province independence (turn non-capital province with burgs into a new state)" class="icon-flag-empty ${separable ? "" : "placeholder"} hide"></span>
|
||||
<span data-tip="Declare province independence (turn non-capital province with burgs into a new state)" class="icon-flag-empty ${
|
||||
separable ? "" : "placeholder"
|
||||
} hide"></span>
|
||||
<span data-tip="Toggle province focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
||||
<span data-tip="Remove the province" class="icon-trash-empty hide"></span>
|
||||
</div>`;
|
||||
|
|
@ -222,74 +231,64 @@ function editProvinces() {
|
|||
function capitalZoomIn(p) {
|
||||
const capital = pack.provinces[p].burg;
|
||||
const l = burgLabels.select("[data-id='" + capital + "']");
|
||||
const x = +l.attr("x"),
|
||||
y = +l.attr("y");
|
||||
const x = +l.attr("x");
|
||||
const y = +l.attr("y");
|
||||
zoomTo(x, y, 8, 2000);
|
||||
}
|
||||
|
||||
function triggerIndependencePromps(p) {
|
||||
alertMessage.innerHTML = "Are you sure you want to declare province independence? <br>It will turn province into a new state";
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
confirmationDialog({
|
||||
title: "Declare independence",
|
||||
buttons: {
|
||||
Declare: function () {
|
||||
declareProvinceIndependence(p);
|
||||
$(this).dialog("close");
|
||||
},
|
||||
Cancel: function () {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
message: "Are you sure you want to declare province independence? <br>It will turn province into a new state",
|
||||
confirm: "Declare",
|
||||
onConfirm: () => {
|
||||
const [oldStateId, newStateId] = declareProvinceIndependence(p);
|
||||
updateStatesPostRelease([oldStateId], [newStateId]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function declareProvinceIndependence(p) {
|
||||
const states = pack.states,
|
||||
provinces = pack.provinces,
|
||||
cells = pack.cells;
|
||||
if (provinces[p].burgs.some(b => pack.burgs[b].capital)) {
|
||||
tip("Cannot declare independence of a province having capital burg. Please change capital first", false, "error");
|
||||
return;
|
||||
}
|
||||
function declareProvinceIndependence(provinceId) {
|
||||
const {states, provinces, cells, burgs} = pack;
|
||||
const province = provinces[provinceId];
|
||||
const {name, burg: burgId, burgs: provinceBurgs} = province;
|
||||
|
||||
const oldState = pack.provinces[p].state;
|
||||
const newState = pack.states.length;
|
||||
if (provinceBurgs.some(b => burgs[b].capital))
|
||||
return tip("Cannot declare independence of a province having capital burg. Please change capital first", false, "error");
|
||||
if (!burgId) return tip("Cannot declare independence of a province without burg", false, "error");
|
||||
|
||||
const oldStateId = province.state;
|
||||
const newStateId = states.length;
|
||||
|
||||
// turn province burg into a capital
|
||||
const burg = provinces[p].burg;
|
||||
if (!burg) return;
|
||||
pack.burgs[burg].capital = 1;
|
||||
moveBurgToGroup(burg, "cities");
|
||||
burgs[burgId].capital = 1;
|
||||
moveBurgToGroup(burgId, "cities");
|
||||
|
||||
// move all burgs to a new state
|
||||
provinces[p].burgs.forEach(b => (pack.burgs[b].state = newState));
|
||||
province.burgs.forEach(b => (burgs[b].state = newStateId));
|
||||
|
||||
// difine new state attributes
|
||||
const center = pack.burgs[burg].cell;
|
||||
const culture = pack.burgs[burg].culture;
|
||||
const name = provinces[p].name;
|
||||
const {cell: center, culture} = burgs[burgId];
|
||||
const color = getRandomColor();
|
||||
|
||||
const coa = provinces[p].coa;
|
||||
const coaEl = document.getElementById("provinceCOA" + p);
|
||||
if (coaEl) coaEl.id = "stateCOA" + newState;
|
||||
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
|
||||
const coa = province.coa;
|
||||
const coaEl = document.getElementById("provinceCOA" + provinceId);
|
||||
if (coaEl) coaEl.id = "stateCOA" + newStateId;
|
||||
emblems.select(`#provinceEmblems > use[data-i='${provinceId}']`).remove();
|
||||
|
||||
// update cells
|
||||
cells.i
|
||||
.filter(i => cells.province[i] === p)
|
||||
.filter(i => cells.province[i] === provinceId)
|
||||
.forEach(i => {
|
||||
cells.province[i] = 0;
|
||||
cells.state[i] = newState;
|
||||
cells.state[i] = newStateId;
|
||||
});
|
||||
|
||||
// update diplomacy and reverse relations
|
||||
const diplomacy = states.map(s => {
|
||||
if (!s.i || s.removed) return "x";
|
||||
let relations = states[oldState].diplomacy[s.i]; // relations between Nth state and old overlord
|
||||
if (s.i === oldState) relations = "Enemy";
|
||||
// new state is Enemy to its old overlord
|
||||
let relations = states[oldStateId].diplomacy[s.i]; // relations between Nth state and old overlord
|
||||
// new state is Enemy to its old owner
|
||||
if (s.i === oldStateId) relations = "Enemy";
|
||||
else if (relations === "Ally") relations = "Suspicion";
|
||||
else if (relations === "Friendly") relations = "Suspicion";
|
||||
else if (relations === "Suspicion") relations = "Neutral";
|
||||
|
|
@ -301,28 +300,51 @@ function editProvinces() {
|
|||
return relations;
|
||||
});
|
||||
diplomacy.push("x");
|
||||
states[0].diplomacy.push([`Independance declaration`, `${name} declared its independance from ${states[oldState].name}`]);
|
||||
states[0].diplomacy.push([`Independance declaration`, `${name} declared its independance from ${states[oldStateId].name}`]);
|
||||
|
||||
// create new state
|
||||
states.push({i: newState, name, diplomacy, provinces: [], color, expansionism: 0.5, capital: burg, type: "Generic", center, culture, military: [], alert: 1, coa});
|
||||
BurgsAndStates.collectStatistics();
|
||||
BurgsAndStates.defineStateForms([newState]);
|
||||
|
||||
if (layerIsOn("toggleProvinces")) toggleProvinces();
|
||||
if (!layerIsOn("toggleStates")) toggleStates();
|
||||
else drawStates();
|
||||
if (!layerIsOn("toggleBorders")) toggleBorders();
|
||||
else drawBorders();
|
||||
BurgsAndStates.drawStateLabels([newState, oldState]);
|
||||
states.push({
|
||||
i: newStateId,
|
||||
name,
|
||||
diplomacy,
|
||||
provinces: [],
|
||||
color,
|
||||
expansionism: 0.5,
|
||||
capital: burgId,
|
||||
type: "Generic",
|
||||
center,
|
||||
culture,
|
||||
military: [],
|
||||
alert: 1,
|
||||
coa
|
||||
});
|
||||
|
||||
// remove old province
|
||||
unfog("focusProvince" + p);
|
||||
if (states[oldState].provinces.includes(p)) states[oldState].provinces.splice(states[oldState].provinces.indexOf(p), 1);
|
||||
provinces[p] = {i: p, removed: true};
|
||||
states[oldStateId].provinces = states[oldStateId].provinces.filter(p => p !== provinceId);
|
||||
provinces[provinceId] = {i: provinceId, removed: true};
|
||||
|
||||
// draw emblem
|
||||
COArenderer.add("state", newState, coa, pack.states[newState].pole[0], pack.states[newState].pole[1]);
|
||||
return [oldStateId, newStateId];
|
||||
}
|
||||
|
||||
function updateStatesPostRelease(oldStates, newStates) {
|
||||
const allStates = unique([...oldStates, ...newStates]);
|
||||
|
||||
layerIsOn("toggleProvinces") && toggleProvinces();
|
||||
layerIsOn("toggleStates") ? drawStates() : toggleStates();
|
||||
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
|
||||
|
||||
BurgsAndStates.collectStatistics();
|
||||
BurgsAndStates.defineStateForms(newStates);
|
||||
BurgsAndStates.drawStateLabels(allStates);
|
||||
|
||||
// redraw emblems
|
||||
allStates.forEach(stateId => {
|
||||
emblems.select(`#stateEmblems > use[data-i='${stateId}']`)?.remove();
|
||||
const {coa, pole} = pack.states[stateId];
|
||||
COArenderer.add("state", stateId, coa, ...pole);
|
||||
});
|
||||
|
||||
unfog();
|
||||
closeDialogs();
|
||||
editStates();
|
||||
}
|
||||
|
|
@ -541,7 +563,17 @@ function editProvinces() {
|
|||
const provinces = pack.provinces
|
||||
.filter(p => p.i && !p.removed)
|
||||
.map(p => {
|
||||
return {id: p.i + states.length - 1, i: p.i, state: p.state, color: p.color, name: p.name, fullName: p.fullName, area: p.area, urban: p.urban, rural: p.rural};
|
||||
return {
|
||||
id: p.i + states.length - 1,
|
||||
i: p.i,
|
||||
state: p.state,
|
||||
color: p.color,
|
||||
name: p.name,
|
||||
fullName: p.fullName,
|
||||
area: p.area,
|
||||
urban: p.urban,
|
||||
rural: p.rural
|
||||
};
|
||||
});
|
||||
const data = states.concat(provinces);
|
||||
const root = d3
|
||||
|
|
@ -564,7 +596,13 @@ function editProvinces() {
|
|||
<option value="urban">Urban population</option>
|
||||
</select>`;
|
||||
alertMessage.innerHTML += `<div id='provinceInfo' class='chartInfo'>‍</div>`;
|
||||
const svg = d3.select("#alertMessage").insert("svg", "#provinceInfo").attr("id", "provincesTree").attr("width", width).attr("height", height).attr("font-size", "10px");
|
||||
const svg = d3
|
||||
.select("#alertMessage")
|
||||
.insert("svg", "#provinceInfo")
|
||||
.attr("id", "provincesTree")
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
.attr("font-size", "10px");
|
||||
const graph = svg.append("g").attr("transform", `translate(10, 0)`);
|
||||
document.getElementById("provincesTreeType").addEventListener("change", updateChart);
|
||||
|
||||
|
|
@ -589,7 +627,14 @@ function editProvinces() {
|
|||
const rural = rn(d.data.rural * populationRate);
|
||||
const urban = rn(d.data.urban * populationRate * urbanization);
|
||||
|
||||
const value = provincesTreeType.value === "area" ? "Area: " + area : provincesTreeType.value === "rural" ? "Rural population: " + si(rural) : provincesTreeType.value === "urban" ? "Urban population: " + si(urban) : "Population: " + si(rural + urban);
|
||||
const value =
|
||||
provincesTreeType.value === "area"
|
||||
? "Area: " + area
|
||||
: provincesTreeType.value === "rural"
|
||||
? "Rural population: " + si(rural)
|
||||
: provincesTreeType.value === "urban"
|
||||
? "Urban population: " + si(urban)
|
||||
: "Population: " + si(rural + urban);
|
||||
|
||||
provinceInfo.innerHTML = `${name}. ${state}. ${value}`;
|
||||
provinceHighlightOn(ev);
|
||||
|
|
@ -637,7 +682,8 @@ function editProvinces() {
|
|||
}
|
||||
|
||||
function updateChart() {
|
||||
const value = this.value === "area" ? d => d.area : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : d => d.rural + d.urban;
|
||||
const value =
|
||||
this.value === "area" ? d => d.area : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : d => d.rural + d.urban;
|
||||
|
||||
root.sum(value);
|
||||
node.data(treeLayout(root).leaves());
|
||||
|
|
@ -681,6 +727,34 @@ function editProvinces() {
|
|||
provs.selectAll("text").call(d3.drag().on("drag", dragLabel)).classed("draggable", true);
|
||||
}
|
||||
|
||||
function triggerProvincesRelease() {
|
||||
confirmationDialog({
|
||||
title: "Release provinces",
|
||||
message: `Are you sure you want to release all provinces?
|
||||
</br>It will turn all separable provinces into independent states.
|
||||
</br>Capital province and provinces without any burgs will state as they are`,
|
||||
confirm: "Release",
|
||||
onConfirm: () => {
|
||||
const oldStateIds = [];
|
||||
const newStateIds = [];
|
||||
|
||||
body.querySelectorAll(":scope > div").forEach(el => {
|
||||
const provinceId = +el.dataset.id;
|
||||
const province = pack.provinces[provinceId];
|
||||
if (!province.burg) return;
|
||||
if (province.burg === pack.states[province.state].capital) return;
|
||||
if (province.burgs.some(burgId => pack.burgs[burgId].capital)) return;
|
||||
|
||||
const [oldStateId, newStateId] = declareProvinceIndependence(provinceId);
|
||||
oldStateIds.push(oldStateId);
|
||||
newStateIds.push(newStateId);
|
||||
});
|
||||
|
||||
updateStatesPostRelease(unique(oldStateIds), newStateIds);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function enterProvincesManualAssignent() {
|
||||
if (!layerIsOn("toggleProvinces")) toggleProvinces();
|
||||
if (!layerIsOn("toggleBorders")) toggleBorders();
|
||||
|
|
@ -783,7 +857,13 @@ function editProvinces() {
|
|||
if (pack.cells.province[i] === provinceNew) exists.remove();
|
||||
else exists.attr("data-province", provinceNew).attr("fill", fill);
|
||||
} else {
|
||||
temp.append("polygon").attr("points", getPackPolygon(i)).attr("data-cell", i).attr("data-province", provinceNew).attr("fill", fill).attr("stroke", "#555");
|
||||
temp
|
||||
.append("polygon")
|
||||
.attr("points", getPackPolygon(i))
|
||||
.attr("data-cell", i)
|
||||
.attr("data-province", provinceNew)
|
||||
.attr("fill", fill)
|
||||
.attr("stroke", "#555");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -839,10 +919,8 @@ function editProvinces() {
|
|||
}
|
||||
|
||||
function enterAddProvinceMode() {
|
||||
if (this.classList.contains("pressed")) {
|
||||
exitAddProvinceMode();
|
||||
return;
|
||||
}
|
||||
if (this.classList.contains("pressed")) return exitAddProvinceMode();
|
||||
|
||||
customization = 12;
|
||||
this.classList.add("pressed");
|
||||
tip("Click on the map to place a new province center", true);
|
||||
|
|
@ -851,24 +929,17 @@ function editProvinces() {
|
|||
}
|
||||
|
||||
function addProvince() {
|
||||
const cells = pack.cells,
|
||||
provinces = pack.provinces;
|
||||
const {cells, provinces} = pack;
|
||||
const point = d3.mouse(this);
|
||||
const center = findCell(point[0], point[1]);
|
||||
if (cells.h[center] < 20) {
|
||||
tip("You cannot place province into the water. Please click on a land cell", false, "error");
|
||||
return;
|
||||
}
|
||||
if (cells.h[center] < 20) return tip("You cannot place province into the water. Please click on a land cell", false, "error");
|
||||
|
||||
const oldProvince = cells.province[center];
|
||||
if (oldProvince && provinces[oldProvince].center === center) {
|
||||
tip("The cell is already a center of a different province. Select other cell", false, "error");
|
||||
return;
|
||||
}
|
||||
if (oldProvince && provinces[oldProvince].center === center)
|
||||
return tip("The cell is already a center of a different province. Select other cell", false, "error");
|
||||
|
||||
const state = cells.state[center];
|
||||
if (!state) {
|
||||
tip("You cannot create a province in neutral lands. Please assign this land to a state first", false, "error");
|
||||
return;
|
||||
}
|
||||
if (!state) return tip("You cannot create a province in neutral lands. Please assign this land to a state first", false, "error");
|
||||
|
||||
if (d3.event.shiftKey === false) exitAddProvinceMode();
|
||||
|
||||
|
|
@ -879,8 +950,8 @@ function editProvinces() {
|
|||
const name = burg ? pack.burgs[burg].name : Names.getState(Names.getCultureShort(c), c);
|
||||
const formName = oldProvince ? provinces[oldProvince].formName : "Province";
|
||||
const fullName = name + " " + formName;
|
||||
const stateColor = pack.states[state].color,
|
||||
rndColor = getRandomColor();
|
||||
const stateColor = pack.states[state].color;
|
||||
const rndColor = getRandomColor();
|
||||
const color = stateColor[0] === "#" ? d3.color(d3.interpolate(stateColor, rndColor)(0.2)).hex() : rndColor;
|
||||
|
||||
// generate emblem
|
||||
|
|
|
|||
|
|
@ -514,6 +514,7 @@ function editStates() {
|
|||
pack.cells.province.forEach((pr, i) => {
|
||||
if (pr === p) pack.cells.province[i] = 0;
|
||||
});
|
||||
|
||||
const coaId = "provinceCOA" + p;
|
||||
if (document.getElementById(coaId)) document.getElementById(coaId).remove();
|
||||
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
|
||||
|
|
@ -901,7 +902,7 @@ function editStates() {
|
|||
states[newOwnerId].provinces.push(provinceId);
|
||||
} else {
|
||||
// new owner is neutral => remove province
|
||||
provinces[provinceId] = {removed: true};
|
||||
provinces[provinceId] = {i: provinceId, removed: true};
|
||||
provinceCells.forEach(i => {
|
||||
cells.province[i] = 0;
|
||||
});
|
||||
|
|
@ -922,7 +923,7 @@ function editStates() {
|
|||
|
||||
// province center is captured by neutrals => remove state
|
||||
if (!stateId) {
|
||||
provinces[provinceId] = {removed: true};
|
||||
provinces[provinceId] = {i: provinceId, removed: true};
|
||||
stateProvinceCells.forEach(i => {
|
||||
cells.province[i] = 0;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,3 +11,7 @@ function common(a, b) {
|
|||
const setB = new Set(b);
|
||||
return [...new Set(a)].filter(a => setB.has(a));
|
||||
}
|
||||
|
||||
function unique(array) {
|
||||
return [...new Set(array)];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue