mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 12:01:23 +01:00
Add the basis for locking everything, code and test the culture locking
This commit is contained in:
parent
0b1a2048a7
commit
520551b14c
7 changed files with 130 additions and 10 deletions
|
|
@ -1438,7 +1438,9 @@ div.states .icon-trash-empty,
|
||||||
div.states .icon-eye,
|
div.states .icon-eye,
|
||||||
div.states .icon-pin,
|
div.states .icon-pin,
|
||||||
div.states .icon-flag-empty,
|
div.states .icon-flag-empty,
|
||||||
div.states .icon-cw {
|
div.states .icon-cw,
|
||||||
|
div.states .icon-lock,
|
||||||
|
div.states .icon-lock-open {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
index.html
10
index.html
|
|
@ -2017,11 +2017,11 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
id="regenerateStates"
|
id="regenerateStates"
|
||||||
data-tip="Click to select new capitals and regenerate states. Emblems and military forces will be regenerated as well, burgs will remain as they are"
|
data-tip="Click to select new capitals and regenerate unlocked states. Emblems and military forces will be regenerated as well, burgs will remain as they are"
|
||||||
>
|
>
|
||||||
States
|
States
|
||||||
</button>
|
</button>
|
||||||
<button id="regenerateProvinces" data-tip="Click to regenerate provinces. States will remain as they are">
|
<button id="regenerateProvinces" data-tip="Click to regenerate unlocked provinces. States will remain as they are">
|
||||||
Provinces
|
Provinces
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|
@ -2031,8 +2031,8 @@
|
||||||
Burgs
|
Burgs
|
||||||
</button>
|
</button>
|
||||||
<button id="regenerateEmblems" data-tip="Click to regenerate all emblems">Emblems</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 unlocked religions">Religions</button>
|
||||||
<button id="regenerateCultures" data-tip="Click to regenerate cultures">Cultures</button>
|
<button id="regenerateCultures" data-tip="Click to regenerate unlocked cultures">Cultures</button>
|
||||||
<button
|
<button
|
||||||
id="regenerateMilitary"
|
id="regenerateMilitary"
|
||||||
data-tip="Click to recalculate military forces based on current military options"
|
data-tip="Click to recalculate military forces based on current military options"
|
||||||
|
|
@ -2040,7 +2040,7 @@
|
||||||
Military
|
Military
|
||||||
</button>
|
</button>
|
||||||
<button id="regenerateIce" data-tip="Click to icebergs and glaciers">Ice</button>
|
<button id="regenerateIce" data-tip="Click to icebergs and glaciers">Ice</button>
|
||||||
<button id="regenerateMarkers" data-tip="Click to regenerate markers">
|
<button id="regenerateMarkers" data-tip="Click to regenerate unlocked markers">
|
||||||
Markers <i id="configRegenerateMarkers" class="icon-cog" data-tip="Click to set number multiplier"></i>
|
Markers <i id="configRegenerateMarkers" class="icon-cog" data-tip="Click to set number multiplier"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ window.Cultures = (function () {
|
||||||
const generate = function () {
|
const generate = function () {
|
||||||
TIME && console.time("generateCultures");
|
TIME && console.time("generateCultures");
|
||||||
cells = pack.cells;
|
cells = pack.cells;
|
||||||
|
const prevCultures = {};
|
||||||
|
if (cells.culture) {
|
||||||
|
cells.culture.forEach(function (cultureId, index) {
|
||||||
|
prevCultures[index] = cultureId;
|
||||||
|
})
|
||||||
|
}
|
||||||
cells.culture = new Uint16Array(cells.i.length); // cell cultures
|
cells.culture = new Uint16Array(cells.i.length); // cell cultures
|
||||||
let count = Math.min(+culturesInput.value, +culturesSet.selectedOptions[0].dataset.max);
|
let count = Math.min(+culturesInput.value, +culturesSet.selectedOptions[0].dataset.max);
|
||||||
|
|
||||||
|
|
@ -51,7 +57,29 @@ window.Cultures = (function () {
|
||||||
const emblemShape = document.getElementById("emblemShape").value;
|
const emblemShape = document.getElementById("emblemShape").value;
|
||||||
|
|
||||||
const codes = [];
|
const codes = [];
|
||||||
|
let unoccupied = [...populated];
|
||||||
cultures.forEach(function (c, i) {
|
cultures.forEach(function (c, i) {
|
||||||
|
if (c.lock) {
|
||||||
|
centers.add(c.center);
|
||||||
|
cells.culture[c.center] = i + 1;
|
||||||
|
codes.push(c.code);
|
||||||
|
|
||||||
|
const cultureCells = [];
|
||||||
|
Object.entries(prevCultures).forEach(function ([index, cultureId]) {
|
||||||
|
if (cultureId === c.i) {
|
||||||
|
cells.culture[index] = i + 1;
|
||||||
|
cultureCells.push(parseInt(index));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
unoccupied = unoccupied.filter(function (cell) {
|
||||||
|
return !cultureCells.includes(cell);
|
||||||
|
});
|
||||||
|
|
||||||
|
c.i = i + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const cell = (c.center = placeCenter(c.sort ? c.sort : i => cells.s[i]));
|
const cell = (c.center = placeCenter(c.sort ? c.sort : i => cells.s[i]));
|
||||||
centers.add(cells.p[cell]);
|
centers.add(cells.p[cell]);
|
||||||
c.i = i + 1;
|
c.i = i + 1;
|
||||||
|
|
@ -70,12 +98,16 @@ window.Cultures = (function () {
|
||||||
function placeCenter(v) {
|
function placeCenter(v) {
|
||||||
let c,
|
let c,
|
||||||
spacing = (graphWidth + graphHeight) / 2 / count;
|
spacing = (graphWidth + graphHeight) / 2 / count;
|
||||||
const sorted = [...populated].sort((a, b) => v(b) - v(a)),
|
// Only use cells where there are no culture already on that cell, which may happen if a locked culture
|
||||||
|
// was restored. We can be sure that locked cultures will always be first in the list.
|
||||||
|
const sorted = [...unoccupied].sort((a, b) => v(b) - v(a)),
|
||||||
max = Math.floor(sorted.length / 2);
|
max = Math.floor(sorted.length / 2);
|
||||||
do {
|
do {
|
||||||
c = sorted[biased(0, max, 5)];
|
c = sorted[biased(0, max, 5)];
|
||||||
spacing *= 0.9;
|
spacing *= 0.9;
|
||||||
} while (centers.find(cells.p[c][0], cells.p[c][1], spacing) !== undefined);
|
} while (
|
||||||
|
centers.find(cells.p[c][0], cells.p[c][1], spacing) !== undefined
|
||||||
|
);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +130,12 @@ window.Cultures = (function () {
|
||||||
const count = Math.min(c, def.length);
|
const count = Math.min(c, def.length);
|
||||||
const cultures = [];
|
const cultures = [];
|
||||||
|
|
||||||
|
if (pack.cultures) {
|
||||||
|
pack.cultures.forEach(function (culture) {
|
||||||
|
if (culture.lock) cultures.push(culture);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (let culture, rnd, i = 0; cultures.length < count && i < 200; i++) {
|
for (let culture, rnd, i = 0; cultures.length < count && i < 200; i++) {
|
||||||
do {
|
do {
|
||||||
rnd = rand(def.length - 1);
|
rnd = rand(def.length - 1);
|
||||||
|
|
@ -481,12 +519,17 @@ window.Cultures = (function () {
|
||||||
|
|
||||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
||||||
pack.cultures.forEach(function (c) {
|
pack.cultures.forEach(function (c) {
|
||||||
if (!c.i || c.removed) return;
|
if (!c.i || c.removed || c.lock) return;
|
||||||
queue.queue({e: c.center, p: 0, c: c.i});
|
queue.queue({e: c.center, p: 0, c: c.i});
|
||||||
});
|
});
|
||||||
|
|
||||||
const neutral = (cells.i.length / 5000) * 3000 * neutralInput.value; // limit cost for culture growth
|
const neutral = (cells.i.length / 5000) * 3000 * neutralInput.value; // limit cost for culture growth
|
||||||
const cost = [];
|
const cost = [];
|
||||||
|
const cellsCost = {};
|
||||||
|
cells.culture.forEach(function (cultureId, index) {
|
||||||
|
// Make the cost of cells with an existing culture so high, they won't get picked
|
||||||
|
cellsCost[index] = cultureId > 0 ? neutral : 0;
|
||||||
|
});
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const next = queue.dequeue(),
|
const next = queue.dequeue(),
|
||||||
n = next.e,
|
n = next.e,
|
||||||
|
|
@ -494,6 +537,7 @@ window.Cultures = (function () {
|
||||||
c = next.c;
|
c = next.c;
|
||||||
const type = pack.cultures[c].type;
|
const type = pack.cultures[c].type;
|
||||||
cells.c[n].forEach(function (e) {
|
cells.c[n].forEach(function (e) {
|
||||||
|
const cellCost = cellsCost[e];
|
||||||
const biome = cells.biome[e];
|
const biome = cells.biome[e];
|
||||||
const biomeCost = getBiomeCost(c, biome, type);
|
const biomeCost = getBiomeCost(c, biome, type);
|
||||||
const biomeChangeCost = biome === cells.biome[n] ? 0 : 20; // penalty on biome change
|
const biomeChangeCost = biome === cells.biome[n] ? 0 : 20; // penalty on biome change
|
||||||
|
|
@ -501,7 +545,7 @@ window.Cultures = (function () {
|
||||||
const riverCost = getRiverCost(cells.r[e], e, type);
|
const riverCost = getRiverCost(cells.r[e], e, type);
|
||||||
const typeCost = getTypeCost(cells.t[e], type);
|
const typeCost = getTypeCost(cells.t[e], type);
|
||||||
const totalCost =
|
const totalCost =
|
||||||
p + (biomeCost + biomeChangeCost + heightCost + riverCost + typeCost) / pack.cultures[c].expansionism;
|
p + cellCost + (biomeCost + biomeChangeCost + heightCost + riverCost + typeCost) / pack.cultures[c].expansionism;
|
||||||
|
|
||||||
if (totalCost > neutral) return;
|
if (totalCost > neutral) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,7 @@ function culturesEditorAddLines() {
|
||||||
style="width: 5em">${si(population)}</div>
|
style="width: 5em">${si(population)}</div>
|
||||||
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
<span data-tip="Click to re-generate names for burgs with this culture assigned" class="icon-arrows-cw hide"></span>
|
||||||
${getShapeOptions(selectShape, c.shield)}
|
${getShapeOptions(selectShape, c.shield)}
|
||||||
|
<span data-tip="Lock culture" class="icon-lock${c.lock ? '' : '-open'} hide"></span>
|
||||||
<span data-tip="Remove culture" class="icon-trash-empty hide"></span>
|
<span data-tip="Remove culture" class="icon-trash-empty hide"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -257,6 +258,8 @@ function culturesEditorAddLines() {
|
||||||
$body.querySelectorAll("div > div.culturePopulation").forEach($el => $el.on("click", changePopulation));
|
$body.querySelectorAll("div > div.culturePopulation").forEach($el => $el.on("click", changePopulation));
|
||||||
$body.querySelectorAll("div > span.icon-arrows-cw").forEach($el => $el.on("click", cultureRegenerateBurgs));
|
$body.querySelectorAll("div > span.icon-arrows-cw").forEach($el => $el.on("click", cultureRegenerateBurgs));
|
||||||
$body.querySelectorAll("div > span.icon-trash-empty").forEach($el => $el.on("click", cultureRemovePrompt));
|
$body.querySelectorAll("div > span.icon-trash-empty").forEach($el => $el.on("click", cultureRemovePrompt));
|
||||||
|
$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));
|
||||||
|
|
||||||
const $culturesHeader = byId("culturesHeader");
|
const $culturesHeader = byId("culturesHeader");
|
||||||
$culturesHeader.querySelector("div[data-sortby='emblems']").style.display = selectShape ? "inline-block" : "none";
|
$culturesHeader.querySelector("div[data-sortby='emblems']").style.display = selectShape ? "inline-block" : "none";
|
||||||
|
|
@ -928,3 +931,21 @@ async function uploadCulturesData() {
|
||||||
drawCultures();
|
drawCultures();
|
||||||
refreshCulturesEditor();
|
refreshCulturesEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLockStatus() {
|
||||||
|
if (customization) return;
|
||||||
|
|
||||||
|
const cultureId = +this.parentNode.dataset.id;
|
||||||
|
const classList = this.classList;
|
||||||
|
const c = pack.cultures[cultureId];
|
||||||
|
c.lock = !c.lock;
|
||||||
|
|
||||||
|
if (c.lock) {
|
||||||
|
classList.remove("icon-lock-open");
|
||||||
|
classList.add("icon-lock");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
classList.remove("icon-lock");
|
||||||
|
classList.add("icon-lock-open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ function religionsEditorAddLines() {
|
||||||
<div data-tip="Religion area" class="religionArea hide" style="width: 5em">${si(area) + unit}</div>
|
<div data-tip="Religion area" class="religionArea hide" style="width: 5em">${si(area) + unit}</div>
|
||||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||||
<div data-tip="${populationTip}" class="religionPopulation hide pointer">${si(population)}</div>
|
<div data-tip="${populationTip}" class="religionPopulation hide pointer">${si(population)}</div>
|
||||||
|
<span data-tip="Lock religion" class="icon-lock${r.lock ? '' : '-open'} hide"></span>
|
||||||
<span data-tip="Remove religion" class="icon-trash-empty hide"></span>
|
<span data-tip="Remove religion" class="icon-trash-empty hide"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -242,6 +243,8 @@ function religionsEditorAddLines() {
|
||||||
$body.querySelectorAll("div > span.icon-arrows-cw").forEach(el => el.on("click", regenerateDeity));
|
$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 > div.religionPopulation").forEach(el => el.on("click", changePopulation));
|
||||||
$body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.on("click", religionRemovePrompt));
|
$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));
|
||||||
|
|
||||||
if ($body.dataset.type === "percentage") {
|
if ($body.dataset.type === "percentage") {
|
||||||
$body.dataset.type = "absolute";
|
$body.dataset.type = "absolute";
|
||||||
|
|
@ -755,3 +758,21 @@ function closeReligionsEditor() {
|
||||||
exitReligionsManualAssignment("close");
|
exitReligionsManualAssignment("close");
|
||||||
exitAddReligionMode();
|
exitAddReligionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLockStatus() {
|
||||||
|
if (customization) return;
|
||||||
|
|
||||||
|
const religionId = +this.parentNode.dataset.id;
|
||||||
|
const classList = this.classList;
|
||||||
|
const r = pack.religions[religionId];
|
||||||
|
r.lock = !r.lock;
|
||||||
|
|
||||||
|
if (r.lock) {
|
||||||
|
classList.remove("icon-lock-open");
|
||||||
|
classList.add("icon-lock");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
classList.remove("icon-lock");
|
||||||
|
classList.add("icon-lock-open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,7 @@ function addListeners() {
|
||||||
else if (classList.contains("statePopulation")) changePopulation(stateId);
|
else if (classList.contains("statePopulation")) changePopulation(stateId);
|
||||||
else if (classList.contains("icon-pin")) toggleFog(stateId, classList);
|
else if (classList.contains("icon-pin")) toggleFog(stateId, classList);
|
||||||
else if (classList.contains("icon-trash-empty")) stateRemovePrompt(stateId);
|
else if (classList.contains("icon-trash-empty")) stateRemovePrompt(stateId);
|
||||||
|
else if (classList.contains("icon-lock") || classList.contains("icon-lock-open")) updateLockStatus(stateId, classList);
|
||||||
});
|
});
|
||||||
|
|
||||||
$body.on("input", function (ev) {
|
$body.on("input", function (ev) {
|
||||||
|
|
@ -288,6 +289,7 @@ function statesEditorAddLines() {
|
||||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||||
<span data-tip="Toggle state focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
<span data-tip="Toggle state focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
||||||
|
<span data-tip="Lock the state" class="icon-lock${s.lock ? '' : '-open'} hide"></span>
|
||||||
<span data-tip="Remove the state" class="icon-trash-empty hide"></span>
|
<span data-tip="Remove the state" class="icon-trash-empty hide"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -1362,3 +1364,17 @@ function closeStatesEditor() {
|
||||||
debug.selectAll(".highlight").remove();
|
debug.selectAll(".highlight").remove();
|
||||||
$body.innerHTML = "";
|
$body.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLockStatus(stateId, classList) {
|
||||||
|
const s = pack.states[stateId];
|
||||||
|
s.lock = !s.lock;
|
||||||
|
|
||||||
|
if (s.lock) {
|
||||||
|
classList.remove("icon-lock-open");
|
||||||
|
classList.add("icon-lock");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
classList.remove("icon-lock");
|
||||||
|
classList.add("icon-lock-open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ function editProvinces() {
|
||||||
else if (cl.contains("culturePopulation")) changePopulation(p);
|
else if (cl.contains("culturePopulation")) changePopulation(p);
|
||||||
else if (cl.contains("icon-pin")) toggleFog(p, cl);
|
else if (cl.contains("icon-pin")) toggleFog(p, cl);
|
||||||
else if (cl.contains("icon-trash-empty")) removeProvince(p);
|
else if (cl.contains("icon-trash-empty")) removeProvince(p);
|
||||||
|
else if (cl.contains("icon-lock") || cl.contains("icon-lock-open")) updateLockStatus(p, cl);
|
||||||
});
|
});
|
||||||
|
|
||||||
body.addEventListener("change", function (ev) {
|
body.addEventListener("change", function (ev) {
|
||||||
|
|
@ -163,6 +164,7 @@ function editProvinces() {
|
||||||
class="icon-flag-empty ${separable ? "" : "placeholder"} hide"
|
class="icon-flag-empty ${separable ? "" : "placeholder"} hide"
|
||||||
></span>
|
></span>
|
||||||
<span data-tip="Toggle province focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
<span data-tip="Toggle province focus" class="icon-pin ${focused ? "" : " inactive"} hide"></span>
|
||||||
|
<span data-tip="Lock the province" class="icon-lock${p.lock ? '' : '-open'} hide"></span>
|
||||||
<span data-tip="Remove the province" class="icon-trash-empty hide"></span>
|
<span data-tip="Remove the province" class="icon-trash-empty hide"></span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
@ -1086,3 +1088,17 @@ function editProvinces() {
|
||||||
if (customization === 12) exitAddProvinceMode();
|
if (customization === 12) exitAddProvinceMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLockStatus(provinceId, classList) {
|
||||||
|
const p = pack.provinces[provinceId];
|
||||||
|
p.lock = !p.lock;
|
||||||
|
|
||||||
|
if (p.lock) {
|
||||||
|
classList.remove("icon-lock-open");
|
||||||
|
classList.add("icon-lock");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
classList.remove("icon-lock");
|
||||||
|
classList.add("icon-lock-open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue