v1.5.05 - emblems regeneration

This commit is contained in:
Azgaar 2021-02-02 23:47:45 +03:00
parent 24d2efe8b6
commit 925e7accbd
8 changed files with 222 additions and 153 deletions

View file

@ -1930,9 +1930,10 @@
<button id="regenerateRoutes" data-tip="Click to regenerate all routes">Routes</button> <button id="regenerateRoutes" data-tip="Click to regenerate all routes">Routes</button>
<button id="regenerateRivers" data-tip="Click to regenerate all rivers (restore default state)">Rivers</button> <button id="regenerateRivers" data-tip="Click to regenerate all rivers (restore default state)">Rivers</button>
<button id="regeneratePopulation" data-tip="Click to recalculate rural and urban population">Population</button> <button id="regeneratePopulation" data-tip="Click to recalculate rural and urban population">Population</button>
<button id="regenerateBurgs" data-tip="Click to regenerate all burgs and routes. States will remain as they are">Burgs</button>
<button id="regenerateStates" data-tip="Click to select new capitals and regenerate states. Military forces will be regenerated as well, burgs will remain as they are">States</button> <button id="regenerateStates" data-tip="Click to select new capitals and regenerate states. Military forces will be regenerated as well, burgs will remain as they are">States</button>
<button id="regenerateProvinces" data-tip="Click to regenerate provinces. States will remain as they are">Provinces</button> <button id="regenerateProvinces" data-tip="Click to regenerate provinces. States will remain as they are">Provinces</button>
<button id="regenerateBurgs" data-tip="Click to regenerate all burgs and routes. States will remain as they are">Burgs</button>
<button id="regenerateEmblems" data-tip="Click to regenerate all emblems">Emblems</button>
<button id="regenerateReligions" data-tip="Click to regenerate religions">Religions</button> <button id="regenerateReligions" data-tip="Click to regenerate religions">Religions</button>
<button id="regenerateCultures" data-tip="Click to regenerate cultures">Cultures</button> <button id="regenerateCultures" data-tip="Click to regenerate cultures">Cultures</button>
<button id="regenerateMilitary" data-tip="Click to recalculate military forces based on current military options">Military</button> <button id="regenerateMilitary" data-tip="Click to recalculate military forces based on current military options">Military</button>

View file

@ -91,7 +91,7 @@
const nomadic = [1, 2, 3, 4].includes(cells.biome[b.cell]); const nomadic = [1, 2, 3, 4].includes(cells.biome[b.cell]);
const type = nomadic ? "Nomadic" : cultures[b.culture].type === "Nomadic" ? "Generic" : cultures[b.culture].type; const type = nomadic ? "Nomadic" : cultures[b.culture].type === "Nomadic" ? "Generic" : cultures[b.culture].type;
const coa = COA.generate(null); const coa = COA.generate(null);
coa.shield = getShield(b.culture, null); coa.shield = COA.getShield(b.culture, null);
states.push({i, color: colors[i-1], name, expansionism, capital: i, type, center: b.cell, culture: b.culture, coa}); states.push({i, color: colors[i-1], name, expansionism, capital: i, type, center: b.cell, culture: b.culture, coa});
cells.burg[b.cell] = i; cells.burg[b.cell] = i;
}); });
@ -139,14 +139,6 @@
} }
} }
function getShield(culture, state) {
const emblemShape = document.getElementById("emblemShape").value;
if (emblemShape === "state" && state && pack.states[state].coa) return pack.states[state].coa.shield;
if (pack.cultures[culture].shield) return pack.cultures[culture].shield;
console.error("Emblem shape is not defined on culture level", pack.cultures[culture]);
return "heater";
}
// define burg coordinates, coa, port status and define details // define burg coordinates, coa, port status and define details
const specifyBurgs = function() { const specifyBurgs = function() {
TIME && console.time("specifyBurgs"); TIME && console.time("specifyBurgs");
@ -194,7 +186,7 @@
else if (b.port) kinship -= .1; else if (b.port) kinship -= .1;
if (b.culture !== state.culture) kinship -= .25; if (b.culture !== state.culture) kinship -= .25;
b.coa = COA.generate(stateCOA, kinship); b.coa = COA.generate(stateCOA, kinship);
b.coa.shield = getShield(b.culture, b.state); b.coa.shield = COA.getShield(b.culture, b.state);
} }
// de-assign port status if it's the only one on feature // de-assign port status if it's the only one on feature
@ -592,6 +584,7 @@
TIME && console.time("collectStatistics"); TIME && console.time("collectStatistics");
const cells = pack.cells, states = pack.states; const cells = pack.cells, states = pack.states;
states.forEach(s => { states.forEach(s => {
if (s.removed) return;
s.cells = s.area = s.burgs = s.rural = s.urban = 0; s.cells = s.area = s.burgs = s.rural = s.urban = 0;
s.neighbors = new Set(); s.neighbors = new Set();
}); });
@ -614,7 +607,10 @@
} }
// convert neighbors Set object into array // convert neighbors Set object into array
states.forEach(s => s.neighbors = Array.from(s.neighbors)); states.forEach(s => {
if (!s.neighbors) return;
s.neighbors = Array.from(s.neighbors);
});
TIME && console.timeEnd("collectStatistics"); TIME && console.timeEnd("collectStatistics");
} }
@ -957,7 +953,7 @@
const color = getMixedColor(s.color); const color = getMixedColor(s.color);
const kinship = nameByBurg ? .8 : .4; const kinship = nameByBurg ? .8 : .4;
const coa = COA.generate(stateBurgs[i].coa, kinship); const coa = COA.generate(stateBurgs[i].coa, kinship);
coa.shield = getShield(c, s.i); coa.shield = COA.getShield(c, s.i);
provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa}); provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa});
} }
}); });
@ -1055,7 +1051,7 @@
const dominion = colony ? P(.95) : singleIsle || isleGroup ? P(.7) : P(.3); const dominion = colony ? P(.95) : singleIsle || isleGroup ? P(.7) : P(.3);
const kinship = dominion ? 0 : .4; const kinship = dominion ? 0 : .4;
const coa = COA.generate(s.coa, kinship, dominion); const coa = COA.generate(s.coa, kinship, dominion);
coa.shield = getShield(c, s.i); coa.shield = COA.getShield(c, s.i);
provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa}); provinces.push({i:province, state:s.i, center, burg, name, formName, fullName, color, coa});
s.provinces.push(province); s.provinces.push(province);

View file

@ -196,18 +196,14 @@
// TODO // TODO
// seafaring // seafaring
// stringify coa on save and load // stringify coa on save and load
// regenerateAll
// generate on new item creation // generate on new item creation
// old versions auto migration: coa generation for cultures and states etc. // old versions auto migration: coa generation for cultures and states etc.
// emblems layer for old maps // emblems layer for old maps
// define emblems layer style for all styles // define emblems layer style for all styles
// add coa on click events for loaded map
// generatate state/prov/burg - remove all rendered coas // generatate state/prov/burg - remove all rendered coas
// remove state/prov/burg - remove rendered coa [burg - done, provice - done, state]
// style settings for emblems layer // style settings for emblems layer
// fix download svg/png // fix map download svg/png
// test in FF // test in FF
// generate all?
// layout preset // layout preset
// burg editor - add emblem // burg editor - add emblem
// other editors // other editors
@ -340,11 +336,13 @@
} }
// dominions have canton with parent coa // dominions have canton with parent coa
if (P(dominion)) { if (P(dominion) && parent.charges) {
const t = getType(parent.t1) === getType(coa.t1) ? getTincture("division", usedTinctures, coa.t1) : parent.t1; const invert = isSameType(parent.t1, coa.t1);
const t = invert ? getTincture("division", usedTinctures, coa.t1) : parent.t1;
const canton = {ordinary: "canton", t}; const canton = {ordinary: "canton", t};
if (coa.charges) { if (coa.charges) {
coa.charges.forEach((charge, i) => { coa.charges.forEach((charge, i) => {
if (charge.size === 1.5) charge.size = 1.4;
if (charge.p.includes("a")) charge.p = charge.p.replaceAll("a", ""); if (charge.p.includes("a")) charge.p = charge.p.replaceAll("a", "");
if (charge.p.includes("j")) charge.p = charge.p.replaceAll("j", ""); if (charge.p.includes("j")) charge.p = charge.p.replaceAll("j", "");
if (charge.p.includes("y")) charge.p = charge.p.replaceAll("y", ""); if (charge.p.includes("y")) charge.p = charge.p.replaceAll("y", "");
@ -352,17 +350,20 @@
}); });
} }
if (parent.charges) {
let charge = parent.charges[0].charge; let charge = parent.charges[0].charge;
if (charge === "inescutcheon" && parent.charges[1]) charge = parent.charges[1].charge; if (charge === "inescutcheon" && parent.charges[1]) charge = parent.charges[1].charge;
let t2 = parent.charges[0].t; let t2 = invert ? parent.t1 : parent.charges[0].t;
if (getType(t) === getType(t2)) t2 = getTincture("charge", usedTinctures, t); if (isSameType(t, t2)) t2 = getTincture("charge", usedTinctures, t);
if (!coa.charges) coa.charges = []; if (!coa.charges) coa.charges = [];
coa.charges.push({charge, t: t2, p: "y", size: 0.5}); coa.charges.push({charge, t: t2, p: "y", size: 0.5});
} else canton.above = 1;
coa.ordinaries ? coa.ordinaries.push(canton) : coa.ordinaries = [canton]; coa.ordinaries ? coa.ordinaries.push(canton) : coa.ordinaries = [canton];
console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(coa)}`));
console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(parent)}`));
console.log("-------");
} }
function selectCharge(set) { function selectCharge(set) {
@ -398,6 +399,18 @@
if (Object.keys(tinctures.stains).includes(tincture)) return "stains"; if (Object.keys(tinctures.stains).includes(tincture)) return "stains";
} }
function isSameType(t1, t2) {
return type(t1) === type(t2);
function type(tincture) {
if (Object.keys(tinctures.metals).includes(tincture)) return "metals";
if (Object.keys(tinctures.colours).includes(tincture)) return "colours";
if (Object.keys(tinctures.stains).includes(tincture)) return "stains";
else return "pattern";
}
}
function definePattern(pattern, element, size = "") { function definePattern(pattern, element, size = "") {
let t1 = null, t2 = null; let t1 = null, t2 = null;
if (P(.15)) size = "-small"; if (P(.15)) size = "-small";
@ -465,19 +478,17 @@
return coa; return coa;
} }
const generateAll = function() { const getShield = function(culture, state) {
const states = pack.states, burgs = pack.burgs, provinces = pack.provinces; const emblemShape = document.getElementById("emblemShape").value;
if (emblemShape === "state" && state && pack.states[state].coa) return pack.states[state].coa.shield;
states.forEach(state => { if (pack.cultures[culture].shield) return pack.cultures[culture].shield;
if (!state.i || state.removed) return; console.error("Emblem shape is not defined on culture level", pack.cultures[culture]);
const coa = generate(); return "heater";
s.coa = coa;
});
} }
const toString = coa => JSON.stringify(coa).replaceAll("#", "%23"); const toString = coa => JSON.stringify(coa).replaceAll("#", "%23");
const copy = coa => JSON.parse(JSON.stringify(coa)); const copy = coa => JSON.parse(JSON.stringify(coa));
return {generate, generateAll, toString, copy}; return {generate, toString, copy, getShield};
}))); })));

View file

@ -3,7 +3,7 @@ function editEmblem(type, id, el) {
if (customization) return; if (customization) return;
if (!id && d3.event) defineEmblemData(d3.event); if (!id && d3.event) defineEmblemData(d3.event);
emblems.selectAll(":scope > use").call(d3.drag().on("drag", dragEmblem)).classed("draggable", true); emblems.selectAll("use").call(d3.drag().on("drag", dragEmblem)).classed("draggable", true);
const emblemStates = document.getElementById("emblemStates"); const emblemStates = document.getElementById("emblemStates");
const emblemProvinces = document.getElementById("emblemProvinces"); const emblemProvinces = document.getElementById("emblemProvinces");
@ -337,6 +337,6 @@ function editEmblem(type, id, el) {
} }
function closeEmblemEditor() { function closeEmblemEditor() {
emblems.selectAll(":scope > use").call(d3.drag().on("drag", null)).attr("class", null); emblems.selectAll("use").call(d3.drag().on("drag", null)).attr("class", null);
} }
} }

View file

@ -1297,32 +1297,23 @@ function drawEmblems() {
.force('collision', d3.forceCollide().radius(d => d.size/2)) .force('collision', d3.forceCollide().radius(d => d.size/2))
.stop(); .stop();
// debug.attr("fill", "#fff").attr("stroke", "#000")
// .selectAll("circle").data(nodes).join("circle")
// .attr("cx", d => d.x)
// .attr("cy", d => d.y)
// .attr("r", 2);
d3.timeout(function() { d3.timeout(function() {
const n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); const n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay()));
for (let i = 0; i < n; ++i) { for (let i = 0; i < n; ++i) {
simulation.tick(); simulation.tick();
} }
emblems.select("#burgEmblems").attr("font-size", sizeBurgs) const burgNodes = nodes.filter(node => node.type === "burg");
.selectAll("use").data(nodes.filter(node => node.type === "burg")).join("use") const burgString = burgNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join("");
.attr("x", d => d.x - d.size / 2).attr("y", d => d.y - d.size / 2) emblems.select("#burgEmblems").attr("font-size", sizeBurgs).html(burgString);
.attr("width", "1em").attr("height", "1em").attr("data-i", d => d.i);
emblems.select("#provinceEmblems").attr("font-size", sizeProvinces) const provinceNodes = nodes.filter(node => node.type === "province");
.selectAll("use").data(nodes.filter(node => node.type === "province")).join("use") const provinceString = provinceNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join("");
.attr("x", d => d.x - d.size / 2).attr("y", d => d.y - d.size / 2) emblems.select("#provinceEmblems").attr("font-size", sizeProvinces).html(provinceString);
.attr("width", "1em").attr("height", "1em").attr("data-i", d => d.i);
emblems.select("#stateEmblems").attr("font-size", sizeStates) const stateNodes = nodes.filter(node => node.type === "state");
.selectAll("use").data(nodes.filter(node => node.type === "state")).join("use") const stateString = stateNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join("");
.attr("x", d => d.x - d.size / 2).attr("y", d => d.y - d.size / 2) emblems.select("#stateEmblems").attr("font-size", sizeStates).html(stateString);
.attr("width", "1em").attr("height", "1em").attr("data-i", d => d.i);
invokeActiveZooming(); invokeActiveZooming();
}); });

View file

@ -352,18 +352,16 @@ function editProvinces() {
pack.cells.province.forEach((province, i) => { pack.cells.province.forEach((province, i) => {
if(province === p) pack.cells.province[i] = 0; if(province === p) pack.cells.province[i] = 0;
}); });
const province = pack.provinces[p];
const s = province.state, state = pack.states[s]; const s = province.state, state = pack.states[s];
if (state.provinces.includes(p)) state.provinces.splice(state.provinces.indexOf(p), 1); if (state.provinces.includes(p)) state.provinces.splice(state.provinces.indexOf(p), 1);
province.removed = true;
unfog("focusProvince"+p); unfog("focusProvince"+p);
if (province.coa) {
const coaId = "provinceCOA" + p; const coaId = "provinceCOA" + p;
if (document.getElementById(coaId)) document.getElementById(coaId).remove(); if (document.getElementById(coaId)) document.getElementById(coaId).remove();
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove(); emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
delete province.coa; // remove to save data
} pack.provinces[p] = {i: p, removed: true};
const g = provs.select("#provincesBody"); const g = provs.select("#provincesBody");
g.select("#province"+p).remove(); g.select("#province"+p).remove();

View file

@ -422,17 +422,28 @@ function editStates() {
statesBody.select("#state"+state).remove(); statesBody.select("#state"+state).remove();
statesBody.select("#state-gap"+state).remove(); statesBody.select("#state-gap"+state).remove();
statesHalo.select("#state-border"+state).remove(); statesHalo.select("#state-border"+state).remove();
labels.select("#stateLabel"+state).remove();
defs.select("#textPath_stateLabel"+state).remove();
unfog("focusState"+state); unfog("focusState"+state);
const label = document.querySelector("#stateLabel"+state);
if (label) label.remove();
pack.burgs.forEach(b => {if(b.state === state) b.state = 0;}); pack.burgs.forEach(b => {if(b.state === state) b.state = 0;});
pack.cells.state.forEach((s, i) => {if(s === state) pack.cells.state[i] = 0;}); pack.cells.state.forEach((s, i) => {if(s === state) pack.cells.state[i] = 0;});
pack.states[state].removed = true;
// remove emblem
const coaId = "stateCOA" + state;
document.getElementById(coaId).remove();
emblems.select(`#stateEmblems > use[data-i='${state}']`).remove();
// remove provinces // remove provinces
pack.states[state].provinces.forEach(p => { pack.states[state].provinces.forEach(p => {
pack.provinces[p].removed = true; pack.provinces[p] = {i: p, removed: true};
pack.cells.province.forEach((pr, i) => {if(pr === p) pack.cells.province[i] = 0;}); 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();
const g = provs.select("#provincesBody");
g.select("#province"+p).remove();
g.select("#province-gap"+p).remove();
}); });
// remove military // remove military
@ -448,8 +459,7 @@ function editStates() {
pack.burgs[capital].state = 0; pack.burgs[capital].state = 0;
moveBurgToGroup(capital, "towns"); moveBurgToGroup(capital, "towns");
// clean state object pack.states[state] = {i: state, removed: true};
pack.states[state].military = [];
debug.selectAll(".highlight").remove(); debug.selectAll(".highlight").remove();
if (!layerIsOn("toggleStates")) toggleStates(); else drawStates(); if (!layerIsOn("toggleStates")) toggleStates(); else drawStates();

View file

@ -60,9 +60,10 @@ function processFeatureRegeneration(event, button) {
if (button === "regenerateRoutes") {Routes.regenerate(); if (!layerIsOn("toggleRoutes")) toggleRoutes();} else if (button === "regenerateRoutes") {Routes.regenerate(); if (!layerIsOn("toggleRoutes")) toggleRoutes();} else
if (button === "regenerateRivers") regenerateRivers(); else if (button === "regenerateRivers") regenerateRivers(); else
if (button === "regeneratePopulation") recalculatePopulation(); else if (button === "regeneratePopulation") recalculatePopulation(); else
if (button === "regenerateBurgs") regenerateBurgs(); else
if (button === "regenerateStates") regenerateStates(); else if (button === "regenerateStates") regenerateStates(); else
if (button === "regenerateProvinces") regenerateProvinces(); else if (button === "regenerateProvinces") regenerateProvinces(); else
if (button === "regenerateBurgs") regenerateBurgs(); else
if (button === "regenerateEmblems") regenerateEmblems(); else
if (button === "regenerateReligions") regenerateReligions(); else if (button === "regenerateReligions") regenerateReligions(); else
if (button === "regenerateCultures") regenerateCultures(); else if (button === "regenerateCultures") regenerateCultures(); else
if (button === "regenerateMilitary") regenerateMilitary(); else if (button === "regenerateMilitary") regenerateMilitary(); else
@ -95,6 +96,108 @@ function recalculatePopulation() {
}); });
} }
function regenerateStates() {
Math.seedrandom(Math.floor(Math.random() * 1e9)); // new random seed
const burgs = pack.burgs.filter(b => b.i && !b.removed);
if (!burgs.length) {
tip("No burgs to generate states. Please create burgs first", false, "error");
return;
}
if (burgs.length < +regionsInput.value) {
tip(`Not enough burgs to generate ${regionsInput.value} states. Will generate only ${burgs.length} states`, false, "warn");
}
// burg local ids sorted by a bit randomized population:
const sorted = burgs.map((b, i) => [i, b.population * Math.random()]).sort((a, b) => b[1] - a[1]).map(b => b[0]);
const capitalsTree = d3.quadtree();
// turn all old capitals into towns
burgs.filter(b => b.capital).forEach(b => {
moveBurgToGroup(b.i, "towns");
b.capital = 0;
});
unfog();
// if desired states number is 0
if (regionsInput.value == 0) {
tip(`Cannot generate zero states. Please check the <i>States Number</i> option`, false, "warn");
pack.states = pack.states.slice(0,1); // remove all except of neutrals
pack.states[0].diplomacy = []; // clear diplomacy
pack.provinces = [0]; // remove all provinces
pack.cells.state = new Uint16Array(pack.cells.i.length); // reset cells data
borders.selectAll("path").remove(); // remove borders
regions.selectAll("path").remove(); // remove states fill
labels.select("#states").selectAll("text"); // remove state labels
defs.select("#textPaths").selectAll("path[id*='stateLabel']").remove(); // remove state labels paths
// remove emblems
document.querySelectorAll("[id^=stateCOA]").forEach(el => el.remove());
document.querySelectorAll("[id^=provinceCOA]").forEach(el => el.remove());
emblems.selectAll("use").remove();
if (document.getElementById("burgsOverviewRefresh").offsetParent) burgsOverviewRefresh.click();
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click();
return;
}
const neutral = pack.states[0].name;
const count = Math.min(+regionsInput.value, burgs.length);
let spacing = (graphWidth + graphHeight) / 2 / count; // min distance between capitals
pack.states = d3.range(count).map(i => {
if (!i) return {i, name: neutral};
let capital = null, x = 0, y = 0;
for (const i of sorted) {
capital = burgs[i];
x = capital.x, y = capital.y;
if (capitalsTree.find(x, y, spacing) === undefined) break;
spacing = Math.max(spacing - 1, 1);
}
capitalsTree.add([x, y]);
capital.capital = 1;
moveBurgToGroup(capital.i, "cities");
const culture = capital.culture;
const basename = capital.name.length < 9 && capital.cell%5 === 0 ? capital.name : Names.getCulture(culture, 3, 6, "", 0);
const name = Names.getState(basename, culture);
const nomadic = [1, 2, 3, 4].includes(pack.cells.biome[capital.cell]);
const type = nomadic ? "Nomadic" : pack.cultures[culture].type === "Nomadic" ? "Generic" : pack.cultures[culture].type;
const expansionism = rn(Math.random() * powerInput.value + 1, 1);
const coa = COA.generate(capital.coa, .3);
coa.shield = capital.coa.shield;
return {i, name, type, capital:capital.i, center:capital.cell, culture, expansionism, coa};
});
BurgsAndStates.expandStates();
BurgsAndStates.normalizeStates();
BurgsAndStates.collectStatistics();
BurgsAndStates.assignColors();
BurgsAndStates.generateCampaigns();
BurgsAndStates.generateDiplomacy();
BurgsAndStates.defineStateForms();
BurgsAndStates.generateProvinces(true);
if (!layerIsOn("toggleStates")) toggleStates(); else drawStates();
if (!layerIsOn("toggleBorders")) toggleBorders(); else drawBorders();
BurgsAndStates.drawStateLabels();
Military.generate();
if (layerIsOn("toggleEmblems")) drawEmblems(); // redrawEmblems
if (document.getElementById("burgsOverviewRefresh").offsetParent) burgsOverviewRefresh.click();
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click();
if (document.getElementById("militaryOverviewRefresh").offsetParent) militaryOverviewRefresh.click();
}
function regenerateProvinces() {
unfog();
BurgsAndStates.generateProvinces(true);
drawBorders();
if (layerIsOn("toggleProvinces")) drawProvinces();
}
function regenerateBurgs() { function regenerateBurgs() {
const cells = pack.cells, states = pack.states; const cells = pack.cells, states = pack.states;
rankCells(); rankCells();
@ -148,96 +251,55 @@ function regenerateBurgs() {
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click(); if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click();
} }
function regenerateStates() { function regenerateEmblems() {
Math.seedrandom(Math.floor(Math.random() * 1e9)); // new random seed // remove old emblems
const burgs = pack.burgs.filter(b => b.i && !b.removed); document.querySelectorAll("[id^=stateCOA]").forEach(el => el.remove());
if (!burgs.length) { document.querySelectorAll("[id^=provinceCOA]").forEach(el => el.remove());
tip("No burgs to generate states. Please create burgs first", false, "error"); document.querySelectorAll("[id^=burgCOA]").forEach(el => el.remove());
return; emblems.selectAll("use").remove();
}
if (burgs.length < +regionsInput.value) {
tip(`Not enough burgs to generate ${regionsInput.value} states. Will generate only ${burgs.length} states`, false, "warn");
}
// burg local ids sorted by a bit randomized population: // generate new emblems
const sorted = burgs.map((b, i) => [i, b.population * Math.random()]).sort((a, b) => b[1] - a[1]).map(b => b[0]); pack.states.forEach(state => {
const capitalsTree = d3.quadtree(); if (!state.i || state.removed) return;
state.coa = COA.generate(null);
// turn all old capitals into towns state.coa.shield = COA.getShield(state.culture, null);
burgs.filter(b => b.capital).forEach(b => {
moveBurgToGroup(b.i, "towns");
b.capital = 0;
}); });
unfog(); pack.burgs.forEach(burg => {
if (!burg.i || burg.removed) return;
const state = pack.states[burg.state];
// if desired states number is 0 let kinship = .25;
if (regionsInput.value == 0) { if (burg.capital) kinship += .1;
tip(`Cannot generate zero states. Please check the <i>States Number</i> option`, false, "warn"); else if (burg.port) kinship -= .1;
pack.states = pack.states.slice(0,1); // remove all except of neutrals if (burg.culture !== state.culture) kinship -= .25;
pack.states[0].diplomacy = []; // clear diplomacy burg.coa = COA.generate(state.coa, kinship);
pack.provinces = [0]; // remove all provinces burg.coa.shield = COA.getShield(burg.culture, burg.state);
pack.cells.state = new Uint16Array(pack.cells.i.length); // reset cells data
borders.selectAll("path").remove(); // remove borders
regions.selectAll("path").remove(); // remove states fill
labels.select("#states").selectAll("text"); // remove state labels
defs.select("#textPaths").selectAll("path[id*='stateLabel']").remove(); // remove state labels paths
if (document.getElementById("burgsOverviewRefresh").offsetParent) burgsOverviewRefresh.click();
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click();
return;
}
const neutral = pack.states[0].name;
const count = Math.min(+regionsInput.value, burgs.length);
let spacing = (graphWidth + graphHeight) / 2 / count; // min distance between capitals
pack.states = d3.range(count).map(i => {
if (!i) return {i, name: neutral};
let capital = null, x = 0, y = 0;
for (const i of sorted) {
capital = burgs[i];
x = capital.x, y = capital.y;
if (capitalsTree.find(x, y, spacing) === undefined) break;
spacing = Math.max(spacing - 1, 1);
}
capitalsTree.add([x, y]);
capital.capital = 1;
moveBurgToGroup(capital.i, "cities");
const culture = capital.culture;
const basename = capital.name.length < 9 && capital.cell%5 === 0 ? capital.name : Names.getCulture(culture, 3, 6, "", 0);
const name = Names.getState(basename, culture);
const nomadic = [1, 2, 3, 4].includes(pack.cells.biome[capital.cell]);
const type = nomadic ? "Nomadic" : pack.cultures[culture].type === "Nomadic" ? "Generic" : pack.cultures[culture].type;
const expansionism = rn(Math.random() * powerInput.value + 1, 1);
return {i, name, type, capital:capital.i, center:capital.cell, culture, expansionism};
}); });
BurgsAndStates.expandStates(); pack.provinces.forEach(province => {
BurgsAndStates.normalizeStates(); if (!province.i || province.removed) return;
BurgsAndStates.collectStatistics(); const parent = province.burg ? pack.burgs[province.burg] : pack.states[province.state];
BurgsAndStates.assignColors();
BurgsAndStates.generateCampaigns();
BurgsAndStates.generateDiplomacy();
BurgsAndStates.defineStateForms();
BurgsAndStates.generateProvinces(true);
if (!layerIsOn("toggleStates")) toggleStates(); else drawStates();
if (!layerIsOn("toggleBorders")) toggleBorders(); else drawBorders();
BurgsAndStates.drawStateLabels();
Military.generate();
if (document.getElementById("burgsOverviewRefresh").offsetParent) burgsOverviewRefresh.click(); let dominion = false;
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click(); if (province.burg) {
if (document.getElementById("militaryOverviewRefresh").offsetParent) militaryOverviewRefresh.click(); dominion = P(.2);
} if (province.formName === "Colony") dominion = P(.95); else
if (province.formName === "Island") dominion = P(.6); else
if (province.formName === "Islands") dominion = P(.5); else
if (province.formName === "Territory") dominion = P(.4); else
if (province.formName === "Land") dominion = P(.3);
}
function regenerateProvinces() { const nameByBurg = province.burg && province.name.slice(0, 3) === parent.name.slice(0, 3);
unfog(); const kinship = dominion ? 0 : nameByBurg ? .8 : .4;
BurgsAndStates.generateProvinces(true); const culture = pack.cells.culture[province.center];
drawBorders();
if (layerIsOn("toggleProvinces")) drawProvinces(); province.coa = COA.generate(parent.coa, kinship, dominion);
province.coa.shield = COA.getShield(culture, province.state);
});
if (layerIsOn("toggleEmblems")) drawEmblems(); // redrawEmblems
} }
function regenerateReligions() { function regenerateReligions() {