diff --git a/index.html b/index.html
index 19795b6a..cb550137 100644
--- a/index.html
+++ b/index.html
@@ -7864,10 +7864,10 @@
-
+
-
+
@@ -7886,7 +7886,7 @@
-
+
diff --git a/main.js b/main.js
index 82787684..e201f7fe 100644
--- a/main.js
+++ b/main.js
@@ -2038,6 +2038,8 @@ const regenerateMap = debounce(async function (options) {
customization = 0;
resetZoom(1000);
undraw();
+ pack.religions = [];
+ pack.cultures = [];
await generate(options);
restoreLayers();
if (ThreeD.options.isOn) ThreeD.redraw();
diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js
index b167b88e..1c0e07a7 100644
--- a/modules/cultures-generator.js
+++ b/modules/cultures-generator.js
@@ -118,8 +118,8 @@ window.Cultures = (function () {
function selectCultures(culturesNumber) {
let def = getDefault(culturesNumber);
-
const cultures = [];
+
pack.cultures?.forEach(function (culture) {
if (culture.lock) cultures.push(culture);
});
diff --git a/modules/dynamic/editors/cultures-editor.js b/modules/dynamic/editors/cultures-editor.js
index 3f8018d6..ac323573 100644
--- a/modules/dynamic/editors/cultures-editor.js
+++ b/modules/dynamic/editors/cultures-editor.js
@@ -519,10 +519,11 @@ function cultureRegenerateBurgs() {
}
function removeCulture(cultureId) {
+ // and the Folk religion
cults.select("#culture" + cultureId).remove();
debug.select("#cultureCenter" + cultureId).remove();
- const {burgs, states, cells, cultures} = pack;
+ const {burgs, states, cells, cultures, religions} = pack;
burgs.filter(b => b.culture == cultureId).forEach(b => (b.culture = 0));
states.forEach(s => {
@@ -531,7 +532,11 @@ function removeCulture(cultureId) {
cells.culture.forEach((c, i) => {
if (c === cultureId) cells.culture[i] = 0;
});
+ cells.religion.forEach((r, i) => {
+ if (r === cultureId) cells.religion[i] = 0;
+ })
cultures[cultureId].removed = true;
+ religions[cultureId].removed = true;
cultures
.filter(c => c.i && !c.removed)
@@ -539,6 +544,12 @@ function removeCulture(cultureId) {
c.origins = c.origins.filter(origin => origin !== cultureId);
if (!c.origins.length) c.origins = [0];
});
+ religions
+ .filter(r => r.i && !r.removed)
+ .forEach(r => {
+ r.origins = r.origins.filter(origin => origin !== cultureId);
+ if (!r.origins.length) r.origins = [0];
+ });
refreshCulturesEditor();
}
@@ -548,7 +559,7 @@ function cultureRemovePrompt() {
const cultureId = +this.parentNode.dataset.id;
confirmationDialog({
title: "Remove culture",
- message: "Are you sure you want to remove the culture?
This action cannot be reverted",
+ message: "Are you sure you want to remove the culture?
The linked folk religion will also be removed.
This action cannot be reverted",
confirm: "Remove",
onConfirm: () => removeCulture(cultureId)
});
@@ -823,6 +834,7 @@ function addCulture() {
if (d3.event.shiftKey === false) exitAddCultureMode();
Cultures.add(center);
+ Religions.addFolk(center);
drawCultureCenters();
culturesEditorAddLines();
diff --git a/modules/dynamic/editors/religions-editor.js b/modules/dynamic/editors/religions-editor.js
index 45d9886f..8a92addc 100644
--- a/modules/dynamic/editors/religions-editor.js
+++ b/modules/dynamic/editors/religions-editor.js
@@ -3,11 +3,11 @@ addListeners();
export function open() {
closeDialogs("#religionsEditor, .stable");
+ if (!layerIsOn("toggleReligions")) toggleReligions();
if (layerIsOn("toggleStates")) toggleStates();
if (layerIsOn("toggleBiomes")) toggleBiomes();
if (layerIsOn("toggleCultures")) toggleCultures();
if (layerIsOn("toggleProvinces")) toggleProvinces();
- if (!layerIsOn("toggleReligions")) toggleReligions();
refreshReligionsEditor();
drawReligionCenters();
@@ -23,13 +23,15 @@ export function open() {
function insertEditorHtml() {
const editorHtml = /* html */ `
-
+
+
+
+
+
`;
@@ -109,6 +116,7 @@ function addListeners() {
byId("religionsManuallyCancel").on("click", () => exitReligionsManualAssignment());
byId("religionsAdd").on("click", enterAddReligionMode);
byId("religionsExport").on("click", downloadReligionsCsv);
+ byId("religionsRecalculate").on("click", () => recalculateReligions(true));
}
function refreshReligionsEditor() {
@@ -166,6 +174,7 @@ function religionsEditorAddLines() {
data-type=""
data-form=""
data-deity=""
+ data-expansion=""
data-expansionism=""
>
@@ -181,6 +190,9 @@ function religionsEditorAddLines() {
${si(area) + unit}
${si(population)}
+
+
+
`;
continue;
}
@@ -195,14 +207,21 @@ function religionsEditorAddLines() {
data-type="${r.type}"
data-form="${r.form}"
data-deity="${r.deity || ""}"
+ data-expansion="${r.expansion}"
data-expansionism="${r.expansionism}"
>
- `
+ }
@@ -212,11 +231,37 @@ function religionsEditorAddLines() {
${si(area) + unit}
${si(population)}
+ ${r.type === "Folk" ?
+ `
+ culture
+
+
+
-
+ `
+ :
+ `
+ ${getExtentOptions(r.expansion)}
+
+
+
+
+ `
+ }
`;
}
$body.innerHTML = lines;
@@ -245,6 +290,8 @@ function religionsEditorAddLines() {
$body.querySelectorAll("div > input.religionDeity").forEach(el => el.on("input", religionChangeDeity));
$body.querySelectorAll("div > span.icon-arrows-cw").forEach(el => el.on("click", regenerateDeity));
$body.querySelectorAll("div > div.religionPopulation").forEach(el => el.on("click", changePopulation));
+ $body.querySelectorAll("div > select.religionExtent").forEach(el => el.on("change", religionChangeExtent));
+ $body.querySelectorAll("div > input.religionExpan").forEach(el => el.on("change", religionChangeExpansionism));
$body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.on("click", religionRemovePrompt));
$body.querySelectorAll("div > span.icon-lock").forEach($el => $el.on("click", updateLockStatus));
$body.querySelectorAll("div > span.icon-lock-open").forEach($el => $el.on("click", updateLockStatus));
@@ -259,7 +306,14 @@ function religionsEditorAddLines() {
function getTypeOptions(type) {
let options = "";
- const types = ["Folk", "Organized", "Cult", "Heresy"];
+ const types = ["Organized", "Cult", "Heresy"];
+ types.forEach(t => (options += ``));
+ return options;
+}
+
+function getExtentOptions(type) {
+ let options = "";
+ const types = ["global", "state", "culture"];
types.forEach(t => (options += ``));
return options;
}
@@ -434,6 +488,20 @@ function changePopulation() {
}
}
+function religionChangeExtent() {
+ const religion = +this.parentNode.dataset.id;
+ this.parentNode.dataset.expansion = this.value;
+ pack.religions[religion].expansion = this.value;
+ recalculateReligions();
+}
+
+function religionChangeExpansionism() {
+ const religion = +this.parentNode.dataset.id;
+ this.parentNode.dataset.expansionism = this.value;
+ pack.religions[religion].expansionism = +this.value;
+ recalculateReligions();
+}
+
function religionRemovePrompt() {
if (customization) return;
@@ -507,6 +575,7 @@ function religionCenterDrag() {
const cell = findCell(x, y);
if (pack.cells.h[cell] < 20) return; // ignore dragging on water
pack.religions[religionId].center = cell;
+ recalculateReligions();
});
}
@@ -584,7 +653,7 @@ function enterReligionsManualAssignent() {
if (!layerIsOn("toggleReligions")) toggleReligions();
customization = 7;
relig.append("g").attr("id", "temp");
- document.querySelectorAll("#religionsBottom > button").forEach(el => (el.style.display = "none"));
+ document.querySelectorAll("#religionsBottom > *").forEach(el => (el.style.display = "none"));
byId("religionsManuallyButtons").style.display = "inline-block";
debug.select("#religionCenters").style("display", "none");
@@ -686,7 +755,7 @@ function exitReligionsManualAssignment(close) {
customization = 0;
relig.select("#temp").remove();
removeCircle();
- document.querySelectorAll("#religionsBottom > button").forEach(el => (el.style.display = "inline-block"));
+ document.querySelectorAll("#religionsBottom > *").forEach(el => (el.style.display = "inline-block"));
byId("religionsManuallyButtons").style.display = "none";
byId("religionsEditor")
@@ -740,15 +809,15 @@ function addReligion() {
function downloadReligionsCsv() {
const unit = getAreaUnit("2");
- const headers = `Id,Name,Color,Type,Form,Supreme Deity,Area ${unit},Believers,Origins`;
+ const headers = `Id,Name,Color,Type,Form,Supreme Deity,Area ${unit},Believers,Origins,Potential,Expansionism`;
const lines = Array.from($body.querySelectorAll(":scope > div"));
const data = lines.map($line => {
- const {id, name, color, type, form, deity, area, population} = $line.dataset;
+ const {id, name, color, type, form, deity, area, population, expansion, expansionism} = $line.dataset;
const deityText = '"' + deity + '"';
const {origins} = pack.religions[+id];
const originList = (origins || []).filter(origin => origin).map(origin => pack.religions[origin].name);
const originText = '"' + originList.join(", ") + '"';
- return [id, name, color, type, form, deityText, area, population, originText].join(",");
+ return [id, name, color, type, form, deityText, area, population, originText, expansion, expansionism].join(",");
});
const csvData = [headers].concat(data).join("\n");
@@ -773,3 +842,13 @@ function updateLockStatus() {
classList.toggle("icon-lock-open");
classList.toggle("icon-lock");
}
+
+function recalculateReligions(must) {
+ if (!must && !religionsAutoChange.checked) return;
+
+ Religions.recalculate();
+
+ drawReligions();
+ refreshReligionsEditor();
+ drawReligionCenters();
+}
diff --git a/modules/religions-generator.js b/modules/religions-generator.js
index 1e85b11d..84d09f67 100644
--- a/modules/religions-generator.js
+++ b/modules/religions-generator.js
@@ -678,6 +678,7 @@ window.Religions = (function () {
const cultureId = cells.culture[cellId];
religionIds[cellId] = cultureToReligionMap.get(cultureId) || 0;
}
+ }
return religionIds;
}
@@ -699,6 +700,32 @@ window.Religions = (function () {
pack.cells.religion = newReligionIds;
}
+ function checkCenters() {
+ const cells = pack.cells;
+ pack.religions.forEach(r => {
+ if (!r.i) return;
+ // move religion center if it's not within religion area after expansion
+ if (r.type==="Folk" || cells.religion[r.center] === r.i) return; // in area, or non-expanding
+ const firstCell = cells.i.find(i => cells.religion[i] === r.i);
+ if (firstCell) r.center = firstCell; // move center, othervise it's an extinct religion
+ });
+ }
+
+ function recalculate() {
+ const {religion, culture} = pack.cells;
+ // start with the culutres map, but also keep locked religions
+ for(const i of pack.cells.i){
+ if( !pack.religions[religion[i]]?.lock ){
+ religion[i] = culture[i];
+ }
+ }
+
+ expandReligions();
+ expandHeresies();
+
+ checkCenters();
+ }
+
const add = function (center) {
const {cells, religions} = pack;
const religionId = cells.religion[center];
@@ -749,10 +776,122 @@ window.Religions = (function () {
cells.religion[center] = i;
};
+ const addFolk = function (center) {
+ const {cultures, religions, cells} = pack;
+
+ const c = cultures.find(c => !c.removed && c.center === center);
+ const codes = religions.map(r => r.code);
+ const newFolk = createFolk(c, codes);
+
+ if(c.i < religions.length){
+ // move an existing organized religion to the end of the array
+ const rCargo = religions[c.i];
+ if(!rCargo.removed && rCargo.type != "Folk") {
+ const newId = religions.length;
+ rCargo.i = newId;
+
+ for(const i of cells.i) {
+ if(cells.religion[i] = c.i) {
+ cells.religion[i] = newId;
+ }
+ }
+ religions.forEach(r => {
+ if (r.i === 0) return;
+ for(let j = 0; j < r.origins.length; j++) {
+ if(r.origins[j] === c.i) {
+ r.origins[j] === newId;
+ return;
+ }
+ }
+ });
+
+ religions.push(rCargo);
+ }
+
+ religions[c.i] = newFolk;
+ }
+ else religions.push(newFolk);
+ };
+
function updateCultures() {
- pack.religions = pack.religions.map((religion, index) => {
- if (index === 0) return religion;
- return {...religion, culture: pack.cells.culture[religion.center]};
+ TIME && console.time("updateCulturesForReligions");
+ const {religions, cultures, cells} = pack;
+
+ const tReligions = [];
+ const spareCovenants = [];
+ const codes = religions.filter(r => !r.removed).map(r => r.code);
+
+ tReligions.push(religions[0]);
+ for (let i = 1; i < cultures.length; i++) {
+ const faith = religions.find(r => r.i === i);
+ if (faith && !faith.removed) {
+ if (faith.type === "Folk") {
+ tReligions.push(faith);
+ continue;
+ }
+ else spareCovenants.push(faith);
+ }
+ const newFolk = createFolk(cultures[i], codes);
+ tReligions.push(newFolk);
+ codes.push(newFolk.code);
+ }
+ for (let i = cultures.length; i < religions.length; i++) {
+ const faith = religions.find(r => r.i === i);
+ if (faith) {
+ if (faith.type === "Folk" && !faith.lock)
+ tReligions.push({...faith, removed: true});
+ else tReligions.push(faith);
+ }
+ else tReligions.push({
+ i,
+ name: "filler index",
+ origins: [null],
+ removed: true
+ });
+ }
+
+ const updateMap = [];
+ for (let k = 0; k < spareCovenants.length; k++) {
+ const sc = spareCovenants[k];
+ const newId = tReligions.length;
+
+ for (const i of cells.i) {
+ if (cells.religion[i] = sc.i) {
+ cells.religion[i] = newId;
+ }
+ }
+
+ updateMap.push({oldId: sc.i, newId});
+ tReligions.forEach(r => {
+ if (r.i === 0) return;
+ for (let i = 0; i < r.origins.length; i++) {
+ if (r.origins[i] === sc.i) {
+ r.origins[i] === newId;
+ return;
+ }
+ }
+ });
+ // update origins from other spareCovenants
+ for (let i = 0; i < sc.origins.length; i++) {
+ const changeRule = updateMap.find(u => u.oldId === sc.origins[i])
+ if (changeRule) sc.origins[i] = changeRule.newId;
+ }
+ tReligions.push({...sc, i: newId});
+ }
+
+ pack.religions = tReligions;
+
+ pack.religions.forEach(r => {
+ if (r.i === 0) return;
+
+ if (r.origins?.length < 1) r.origins = [0];
+
+ if (r.type === "Folk" && cultures[r.i]) {
+ r.center = cultures[r.i].center;
+ }
+ else {
+ r.culture = cells.culture[r.center];
+ }
});
}
diff --git a/modules/ui/editors.js b/modules/ui/editors.js
index 23798861..def092fe 100644
--- a/modules/ui/editors.js
+++ b/modules/ui/editors.js
@@ -1188,6 +1188,6 @@ async function editCultures() {
async function editReligions() {
if (customization) return;
- const Editor = await import("../dynamic/editors/religions-editor.js?v=1.88.07");
+ const Editor = await import("../dynamic/editors/religions-editor.js?v=1.90.00");
Editor.open();
}
diff --git a/versioning.js b/versioning.js
index c901a46a..32386e54 100644
--- a/versioning.js
+++ b/versioning.js
@@ -28,6 +28,7 @@ const version = "1.89.08"; // generator version, update each time
Latest changes:
+ - Religions can be edited and redrawn like cultures
- Lock states, provinces, cultures, and religions from regeneration
- Heightmap brushes: linear edit option
- Data Charts screen