buttons to release all provinces and regenerate culture name

This commit is contained in:
Azgaar 2021-11-07 18:57:52 +03:00
parent 567cf3676a
commit 6de70f5897
8 changed files with 301 additions and 149 deletions

View file

@ -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;

View file

@ -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

View file

@ -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'>&#8205;</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);
});
}

View file

@ -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'>&#8205;</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

View file

@ -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;
});