mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
feat: burg group editor - form
This commit is contained in:
parent
511d8f37d8
commit
b6708bf698
11 changed files with 274 additions and 68 deletions
15
index.html
15
index.html
|
|
@ -5348,16 +5348,21 @@
|
||||||
<col style="width: 4em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 4em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 4em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 5em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 5em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 5em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 5em" />
|
<col style="width: 4em" />
|
||||||
<col style="width: 5em" />
|
<col style="width: 4em" />
|
||||||
|
<col style="width: 1em" />
|
||||||
|
<col style="width: 1em" />
|
||||||
|
<col style="width: 1em" />
|
||||||
|
<col style="width: 1em" />
|
||||||
<col style="width: 1em" />
|
<col style="width: 1em" />
|
||||||
<col style="width: 1em" />
|
<col style="width: 1em" />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th data-tip="Rendering order: higher values are rendered on top">Order</th>
|
||||||
<th data-tip="Type group name">Name</th>
|
<th data-tip="Type group name">Name</th>
|
||||||
<th data-tip="Set min population constraint" colspan="2">Population</th>
|
<th data-tip="Set min population constraint" colspan="2">Population</th>
|
||||||
<th data-tip="Set population percentile: 0-100, where 90 means the burg must have a population higher than 90% of all burgs">Percentile</th>
|
<th data-tip="Set population percentile: 0-100, where 90 means the burg must have a population higher than 90% of all burgs">Percentile</th>
|
||||||
|
|
|
||||||
11
main.js
11
main.js
|
|
@ -171,7 +171,8 @@ let options = {
|
||||||
|
|
||||||
// create groups for each burg type
|
// create groups for each burg type
|
||||||
{
|
{
|
||||||
for (const {name} of options.burgs.groups) {
|
const sortedGroups = [...options.burgs.groups].sort((a, b) => a.order - b.order);
|
||||||
|
for (const {name} of sortedGroups) {
|
||||||
burgIcons.append("g").attr("id", name);
|
burgIcons.append("g").attr("id", name);
|
||||||
burgLabels.append("g").attr("id", name);
|
burgLabels.append("g").attr("id", name);
|
||||||
}
|
}
|
||||||
|
|
@ -661,14 +662,18 @@ async function generate(options) {
|
||||||
rankCells();
|
rankCells();
|
||||||
Cultures.generate();
|
Cultures.generate();
|
||||||
Cultures.expand();
|
Cultures.expand();
|
||||||
|
|
||||||
Burgs.generate();
|
Burgs.generate();
|
||||||
States.generate();
|
States.generate();
|
||||||
Routes.generate();
|
Routes.generate();
|
||||||
Religions.generate();
|
Religions.generate();
|
||||||
|
|
||||||
|
Burgs.specify();
|
||||||
|
States.collectStatistics();
|
||||||
States.defineStateForms();
|
States.defineStateForms();
|
||||||
|
|
||||||
Provinces.generate();
|
Provinces.generate();
|
||||||
Provinces.getPoles();
|
Provinces.getPoles();
|
||||||
Burgs.specify();
|
|
||||||
|
|
||||||
Rivers.specify();
|
Rivers.specify();
|
||||||
Features.specify();
|
Features.specify();
|
||||||
|
|
@ -695,7 +700,7 @@ async function generate(options) {
|
||||||
title: "Generation error",
|
title: "Generation error",
|
||||||
width: "32em",
|
width: "32em",
|
||||||
buttons: {
|
buttons: {
|
||||||
"Cleanup data": cleanupData,
|
"Cleanup data": () => cleanupData(),
|
||||||
Regenerate: function () {
|
Regenerate: function () {
|
||||||
regenerateMap("generation error");
|
regenerateMap("generation error");
|
||||||
$(this).dialog("close");
|
$(this).dialog("close");
|
||||||
|
|
|
||||||
|
|
@ -261,12 +261,13 @@ window.Burgs = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDefaultGroups = () => [
|
const getDefaultGroups = () => [
|
||||||
{name: "capitals", active: true, features: {capital: true}, preview: "watabou-city-generator"},
|
{name: "capitals", active: true, order: 9, features: {capital: true}, preview: "watabou-city-generator"},
|
||||||
{name: "cities", active: true, percentile: 90, min: 5, preview: "watabou-city-generator"},
|
{name: "cities", active: true, order: 8, percentile: 90, min: 5, preview: "watabou-city-generator"},
|
||||||
{
|
{
|
||||||
name: "forts",
|
name: "forts",
|
||||||
active: true,
|
active: true,
|
||||||
features: {citadel: true, walls: false, plaza: false, port: false},
|
features: {citadel: true, walls: false, plaza: false, port: false},
|
||||||
|
order: 6,
|
||||||
max: 1,
|
max: 1,
|
||||||
preview: null
|
preview: null
|
||||||
},
|
},
|
||||||
|
|
@ -274,6 +275,7 @@ window.Burgs = (() => {
|
||||||
name: "monasteries",
|
name: "monasteries",
|
||||||
active: true,
|
active: true,
|
||||||
features: {temple: true, walls: false, plaza: false, port: false},
|
features: {temple: true, walls: false, plaza: false, port: false},
|
||||||
|
order: 5,
|
||||||
max: 0.8,
|
max: 0.8,
|
||||||
preview: null
|
preview: null
|
||||||
},
|
},
|
||||||
|
|
@ -281,6 +283,7 @@ window.Burgs = (() => {
|
||||||
name: "caravanserais",
|
name: "caravanserais",
|
||||||
active: true,
|
active: true,
|
||||||
features: {port: false, plaza: true},
|
features: {port: false, plaza: true},
|
||||||
|
order: 4,
|
||||||
max: 0.8,
|
max: 0.8,
|
||||||
biomes: [1, 2, 3],
|
biomes: [1, 2, 3],
|
||||||
preview: null
|
preview: null
|
||||||
|
|
@ -288,6 +291,7 @@ window.Burgs = (() => {
|
||||||
{
|
{
|
||||||
name: "trading_posts",
|
name: "trading_posts",
|
||||||
active: true,
|
active: true,
|
||||||
|
order: 3,
|
||||||
features: {plaza: true},
|
features: {plaza: true},
|
||||||
max: 0.8,
|
max: 0.8,
|
||||||
biomes: [5, 6, 7, 8, 9, 10, 11, 12],
|
biomes: [5, 6, 7, 8, 9, 10, 11, 12],
|
||||||
|
|
@ -296,6 +300,7 @@ window.Burgs = (() => {
|
||||||
{
|
{
|
||||||
name: "villages",
|
name: "villages",
|
||||||
active: true,
|
active: true,
|
||||||
|
order: 2,
|
||||||
min: 0.1,
|
min: 0.1,
|
||||||
max: 2,
|
max: 2,
|
||||||
features: {walls: false},
|
features: {walls: false},
|
||||||
|
|
@ -304,11 +309,12 @@ window.Burgs = (() => {
|
||||||
{
|
{
|
||||||
name: "hamlets",
|
name: "hamlets",
|
||||||
active: true,
|
active: true,
|
||||||
|
order: 1,
|
||||||
features: {walls: false, plaza: false},
|
features: {walls: false, plaza: false},
|
||||||
max: 0.1,
|
max: 0.1,
|
||||||
preview: "watabou-village-generator"
|
preview: "watabou-village-generator"
|
||||||
},
|
},
|
||||||
{name: "towns", active: true, isDefault: true, preview: "watabou-city-generator"}
|
{name: "towns", active: true, order: 7, isDefault: true, preview: "watabou-city-generator"}
|
||||||
];
|
];
|
||||||
|
|
||||||
function defineGroup(burg, populations) {
|
function defineGroup(burg, populations) {
|
||||||
|
|
|
||||||
|
|
@ -1253,6 +1253,8 @@ function addState() {
|
||||||
coa,
|
coa,
|
||||||
pole
|
pole
|
||||||
});
|
});
|
||||||
|
|
||||||
|
States.findNeighbors();
|
||||||
States.collectStatistics();
|
States.collectStatistics();
|
||||||
States.defineStateForms([newState]);
|
States.defineStateForms([newState]);
|
||||||
adjustProvinces([cells.province[center]]);
|
adjustProvinces([cells.province[center]]);
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,11 @@ window.States = (() => {
|
||||||
const generate = () => {
|
const generate = () => {
|
||||||
TIME && console.time("generateStates");
|
TIME && console.time("generateStates");
|
||||||
pack.states = createStates();
|
pack.states = createStates();
|
||||||
|
|
||||||
expandStates();
|
expandStates();
|
||||||
normalizeStates();
|
normalize();
|
||||||
getPoles();
|
getPoles();
|
||||||
|
findNeighbors();
|
||||||
collectStatistics();
|
|
||||||
assignColors();
|
assignColors();
|
||||||
|
|
||||||
generateCampaigns();
|
generateCampaigns();
|
||||||
generateDiplomacy();
|
generateDiplomacy();
|
||||||
|
|
||||||
|
|
@ -144,7 +141,7 @@ window.States = (() => {
|
||||||
TIME && console.timeEnd("expandStates");
|
TIME && console.timeEnd("expandStates");
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeStates = () => {
|
const normalize = () => {
|
||||||
TIME && console.time("normalizeStates");
|
TIME && console.time("normalizeStates");
|
||||||
const {cells, burgs} = pack;
|
const {cells, burgs} = pack;
|
||||||
|
|
||||||
|
|
@ -174,14 +171,11 @@ window.States = (() => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// calculate states data like area, population etc.
|
const findNeighbors = () => {
|
||||||
const collectStatistics = () => {
|
|
||||||
TIME && console.time("collectStatistics");
|
|
||||||
const {cells, states} = pack;
|
const {cells, states} = pack;
|
||||||
|
|
||||||
states.forEach(s => {
|
states.forEach(s => {
|
||||||
if (s.removed) return;
|
if (s.removed) return;
|
||||||
s.cells = s.area = s.burgs = s.rural = s.urban = 0;
|
|
||||||
s.neighbors = new Set();
|
s.neighbors = new Set();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -189,28 +183,16 @@ window.States = (() => {
|
||||||
if (cells.h[i] < 20) continue;
|
if (cells.h[i] < 20) continue;
|
||||||
const s = cells.state[i];
|
const s = cells.state[i];
|
||||||
|
|
||||||
// check for neighboring states
|
|
||||||
cells.c[i]
|
cells.c[i]
|
||||||
.filter(c => cells.h[c] >= 20 && cells.state[c] !== s)
|
.filter(c => cells.h[c] >= 20 && cells.state[c] !== s)
|
||||||
.forEach(c => states[s].neighbors.add(cells.state[c]));
|
.forEach(c => states[s].neighbors.add(cells.state[c]));
|
||||||
|
|
||||||
// collect stats
|
|
||||||
states[s].cells += 1;
|
|
||||||
states[s].area += cells.area[i];
|
|
||||||
states[s].rural += cells.pop[i];
|
|
||||||
if (cells.burg[i]) {
|
|
||||||
states[s].urban += pack.burgs[cells.burg[i]].population;
|
|
||||||
states[s].burgs++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert neighbors Set object into array
|
// convert neighbors Set object into array
|
||||||
states.forEach(s => {
|
states.forEach(s => {
|
||||||
if (!s.neighbors) return;
|
if (!s.neighbors || s.removed) return;
|
||||||
s.neighbors = Array.from(s.neighbors);
|
s.neighbors = Array.from(s.neighbors);
|
||||||
});
|
});
|
||||||
|
|
||||||
TIME && console.timeEnd("collectStatistics");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const assignColors = () => {
|
const assignColors = () => {
|
||||||
|
|
@ -238,6 +220,33 @@ window.States = (() => {
|
||||||
TIME && console.timeEnd("assignColors");
|
TIME && console.timeEnd("assignColors");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// calculate states data like area, population etc.
|
||||||
|
const collectStatistics = () => {
|
||||||
|
TIME && console.time("collectStatistics");
|
||||||
|
const {cells, states} = pack;
|
||||||
|
|
||||||
|
states.forEach(s => {
|
||||||
|
if (s.removed) return;
|
||||||
|
s.cells = s.area = s.burgs = s.rural = s.urban = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const i of cells.i) {
|
||||||
|
if (cells.h[i] < 20) continue;
|
||||||
|
const s = cells.state[i];
|
||||||
|
|
||||||
|
// collect stats
|
||||||
|
states[s].cells += 1;
|
||||||
|
states[s].area += cells.area[i];
|
||||||
|
states[s].rural += cells.pop[i];
|
||||||
|
if (cells.burg[i]) {
|
||||||
|
states[s].urban += pack.burgs[cells.burg[i]].population;
|
||||||
|
states[s].burgs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TIME && console.timeEnd("collectStatistics");
|
||||||
|
};
|
||||||
|
|
||||||
const wars = {
|
const wars = {
|
||||||
War: 6,
|
War: 6,
|
||||||
Conflict: 2,
|
Conflict: 2,
|
||||||
|
|
@ -614,8 +623,9 @@ window.States = (() => {
|
||||||
return {
|
return {
|
||||||
generate,
|
generate,
|
||||||
expandStates,
|
expandStates,
|
||||||
normalizeStates,
|
normalize,
|
||||||
getPoles,
|
getPoles,
|
||||||
|
findNeighbors,
|
||||||
assignColors,
|
assignColors,
|
||||||
collectStatistics,
|
collectStatistics,
|
||||||
generateCampaign,
|
generateCampaign,
|
||||||
|
|
|
||||||
|
|
@ -31,22 +31,23 @@ function editBurgGroups() {
|
||||||
// add listeners
|
// add listeners
|
||||||
byId("burgGroupsForm").on("change", validateForm).on("submit", submitForm);
|
byId("burgGroupsForm").on("change", validateForm).on("submit", submitForm);
|
||||||
byId("burgGroupsBody").on("click", ev => {
|
byId("burgGroupsBody").on("click", ev => {
|
||||||
const line = ev.target.closest("tr");
|
const el = ev.target;
|
||||||
if (line && ev.target.classList.contains("removeGroup")) {
|
const line = el.closest("tr");
|
||||||
const lines = byId("burgGroupsBody").children;
|
if (!line) return;
|
||||||
if (lines.length < 2) return tip("At least one group should be defined", false, "error");
|
|
||||||
|
|
||||||
confirmationDialog({
|
if (el.name === "biomes") {
|
||||||
title: this.dataset.tip,
|
const biomes = Array(biomesData.i.length)
|
||||||
message:
|
.fill(null)
|
||||||
"Are you sure you want to remove the group? <br>This WON'T change the burgs unless the changes are applied",
|
.map((_, i) => ({i, name: biomesData.name[i], color: biomesData.color[i]}));
|
||||||
confirm: "Remove",
|
return selectLimitation(el, biomes);
|
||||||
onConfirm: () => {
|
|
||||||
line.remove();
|
|
||||||
validateForm();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (el.name === "states") return selectLimitation(el, pack.states);
|
||||||
|
if (el.name === "cultures") return selectLimitation(el, pack.cultures);
|
||||||
|
if (el.name === "religions") return selectLimitation(el, pack.religions);
|
||||||
|
if (el.name === "features") return selectFeaturesLimitation(el);
|
||||||
|
if (el.name === "up") return line.parentNode.insertBefore(line, line.previousElementSibling);
|
||||||
|
if (el.name === "down") return line.parentNode.insertBefore(line.nextElementSibling, line);
|
||||||
|
if (el.name === "remove") return removeLine(line);
|
||||||
});
|
});
|
||||||
|
|
||||||
function addLines() {
|
function addLines() {
|
||||||
|
|
@ -58,22 +59,183 @@ function editBurgGroups() {
|
||||||
const count = pack.burgs.filter(burg => !burg.removed && burg.group === group.name).length;
|
const count = pack.burgs.filter(burg => !burg.removed && burg.group === group.name).length;
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return /* html */ `<tr name="${group.name}">
|
return /* html */ `<tr name="${group.name}">
|
||||||
|
<td data-tip="Rendering order: higher values are rendered on top"><input type="number" name="order" min="1" max="999" step="1" required value="${group.order || ''}" /></td>
|
||||||
<td data-tip="Type group name. It can contain only text, digits and underscore"><input type="text" name="name" value="${group.name}" required pattern="\\w+" /></td>
|
<td data-tip="Type group name. It can contain only text, digits and underscore"><input type="text" name="name" value="${group.name}" required pattern="\\w+" /></td>
|
||||||
<td data-tip="Set min population constraint"><input type="number" name="min" min="0" step="any" value="${group.min || ''}" /></td>
|
<td data-tip="Set min population constraint"><input type="number" name="min" min="0" step="any" value="${group.min || ''}" /></td>
|
||||||
<td data-tip="Set max population constraint"><input type="number" name="max" min="0" step="any" value="${group.max || ''}" /></td>
|
<td data-tip="Set max population constraint"><input type="number" name="max" min="0" step="any" value="${group.max || ''}" /></td>
|
||||||
<td data-tip="Set population percentile"><input type="number" name="percentile" min="0" max="100" step="any" value="${group.percentile || ''}" /></td>
|
<td data-tip="Set population percentile"><input type="number" name="percentile" min="0" max="100" step="any" value="${group.percentile || ''}" /></td>
|
||||||
<td data-tip="Select allowed biomes"><button type="button" name="biomes">${group.biomes ? "some" : "all"}</button></td>
|
<td data-tip="Select allowed biomes">
|
||||||
<td data-tip="Select allowed states"><button type="button" name="states">${group.states ? "some" : "all"}</button></td>
|
<input type="hidden" name="biomes" value="${group.biomes || ""}">
|
||||||
<td data-tip="Select allowed cultures"><button type="button" name="cultures">${group.cultures ? "some" : "all"}</button></td>
|
<button type="button" name="biomes">${group.biomes ? "some" : "all"}</button>
|
||||||
<td data-tip="Select allowed religions"><button type="button" name="religions">${group.religions ? "some" : "all"}</button></td>
|
</td>
|
||||||
<td data-tip="Select allowed features" ><button type="button" name="features">${group.features ? "some" : "all"}</button></td>
|
<td data-tip="Select allowed states">
|
||||||
|
<input type="hidden" name="states" value="${group.states || ""}">
|
||||||
|
<button type="button" name="states">${group.states ? "some" : "all"}</button>
|
||||||
|
</td>
|
||||||
|
<td data-tip="Select allowed cultures">
|
||||||
|
<input type="hidden" name="cultures" value="${group.cultures || ""}">
|
||||||
|
<button type="button" name="cultures">${group.cultures ? "some" : "all"}</button>
|
||||||
|
</td>
|
||||||
|
<td data-tip="Select allowed religions">
|
||||||
|
<input type="hidden" name="religions" value="${group.religions || ""}">
|
||||||
|
<button type="button" name="religions">${group.religions ? "some" : "all"}</button>
|
||||||
|
</td>
|
||||||
|
<td data-tip="Select allowed features" >
|
||||||
|
<input type="hidden" name="features" value='${JSON.stringify(group.features || {})}'>
|
||||||
|
<button type="button" name="features">${Object.keys(group.features || {}).length ? "some" : "any"}</button>
|
||||||
|
</td>
|
||||||
<td data-tip="Number of burgs in group">${count}</td>
|
<td data-tip="Number of burgs in group">${count}</td>
|
||||||
<td data-tip="Activate/deactivate group"><input type="checkbox" name="active" class="native" ${group.active && "checked"} /></td>
|
<td data-tip="Activate/deactivate group"><input type="checkbox" name="active" class="native" ${group.active && "checked"} /></td>
|
||||||
<td data-tip="Select group to be assigned if other groups are not passed"><input type="radio" name="isDefault" ${group.isDefault && "checked"}></td>
|
<td data-tip="Select group to be assigned if other groups are not passed"><input type="radio" name="isDefault" ${group.isDefault && "checked"}></td>
|
||||||
<td data-tip="Remove group"><button type="button" class="icon-trash-empty removeGroup"></button></td>
|
<td data-tip="Assignment order: move group up"><button type="button" name="up" class="icon-up-big"></button></td>
|
||||||
|
<td data-tip="Assignment order: move group down"><button type="button" name="down" class="icon-down-big"></button></td>
|
||||||
|
<td data-tip="Remove group"><button type="button" name="remove" class="icon-trash"></button></td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectLimitation(el, data) {
|
||||||
|
const value = el.previousElementSibling.value;
|
||||||
|
const initial = value ? value.split(",").map(v => +v) : [];
|
||||||
|
|
||||||
|
const filtered = data.filter(datum => datum.i && !datum.removed);
|
||||||
|
const lines = filtered.map(
|
||||||
|
({i, name, fullName, color}) => /* html */ `
|
||||||
|
<tr data-tip="${name}">
|
||||||
|
<td>
|
||||||
|
<span style="color:${color}">⬤</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input data-i="${i}" id="el${i}" type="checkbox" class="checkbox" ${
|
||||||
|
!initial.length || initial.includes(i) ? "checked" : ""
|
||||||
|
} >
|
||||||
|
<label for="el${i}" class="checkbox-label">${fullName || name}</label>
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
|
);
|
||||||
|
|
||||||
|
alertMessage.innerHTML = /* html */ `<b>Limit group by ${el.name}:</b>
|
||||||
|
<table style="margin-top:.3em">
|
||||||
|
<tbody>
|
||||||
|
${lines.join("")}
|
||||||
|
</tbody>
|
||||||
|
</table>`;
|
||||||
|
|
||||||
|
$("#alert").dialog({
|
||||||
|
width: fitContent(),
|
||||||
|
title: "Limit group",
|
||||||
|
buttons: {
|
||||||
|
Invert: function () {
|
||||||
|
alertMessage.querySelectorAll("input").forEach(el => (el.checked = !el.checked));
|
||||||
|
},
|
||||||
|
Apply: function () {
|
||||||
|
const inputs = Array.from(alertMessage.querySelectorAll("input"));
|
||||||
|
const selected = inputs.reduce((acc, input) => {
|
||||||
|
if (input.checked) acc.push(input.dataset.i);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!selected.length) return tip("Select at least one element", false, "error");
|
||||||
|
|
||||||
|
const allAreSelected = selected.length === inputs.length;
|
||||||
|
el.previousElementSibling.value = allAreSelected ? "" : selected.join(",");
|
||||||
|
el.innerHTML = allAreSelected ? "all" : "some";
|
||||||
|
$(this).dialog("close");
|
||||||
|
},
|
||||||
|
Cancel: function () {
|
||||||
|
$(this).dialog("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectFeaturesLimitation(el) {
|
||||||
|
const value = el.previousElementSibling.value;
|
||||||
|
const initial = value ? JSON.parse(value) : {};
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{name: "capital", icon: "icon-star"},
|
||||||
|
{name: "port", icon: "icon-anchor"},
|
||||||
|
{name: "citadel", icon: "icon-chess-rook"},
|
||||||
|
{name: "walls", icon: "icon-fort-awesome"},
|
||||||
|
{name: "plaza", icon: "icon-store"},
|
||||||
|
{name: "temple", icon: "icon-chess-bishop"},
|
||||||
|
{name: "shanty", icon: "icon-campground"}
|
||||||
|
];
|
||||||
|
|
||||||
|
const lines = features.map(
|
||||||
|
// prettier-ignore
|
||||||
|
({name, icon}) => /* html */ `
|
||||||
|
<tr data-tip="Select limitation for burg feature: ${name}">
|
||||||
|
<td>
|
||||||
|
<span class="${icon}"></span>
|
||||||
|
<span style="margin-left:.2em">${name}</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="${name}" value="true" ${initial[name] === true ? "checked" : ""} style="margin:0" >
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="${name}" value="false" ${initial[name] === false ? "checked" : ""} style="margin:0">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="${name}" value="undefined" ${initial[name] === undefined ? "checked" : ""} style="margin:0">
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
|
);
|
||||||
|
|
||||||
|
alertMessage.innerHTML = /* html */ `
|
||||||
|
<form id="featuresLimitationForm">
|
||||||
|
<table>
|
||||||
|
<thead style="font-weight:bold">
|
||||||
|
<td style="width:6em">Features</td>
|
||||||
|
<td style="width:3em">True</td>
|
||||||
|
<td style="width:3em">False</td>
|
||||||
|
<td style="width:3em">Any</td>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${lines.join("")}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</form>`;
|
||||||
|
|
||||||
|
$("#alert").dialog({
|
||||||
|
width: fitContent(),
|
||||||
|
title: "Limit group by features",
|
||||||
|
buttons: {
|
||||||
|
Apply: function () {
|
||||||
|
const form = byId("featuresLimitationForm");
|
||||||
|
const values = features.reduce((acc, {name}) => {
|
||||||
|
const value = form[name].value;
|
||||||
|
if (value !== "undefined") acc[name] = value === "true";
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
el.previousElementSibling.value = JSON.stringify(values);
|
||||||
|
el.innerHTML = Object.keys(values).length ? "some" : "any";
|
||||||
|
$(this).dialog("close");
|
||||||
|
},
|
||||||
|
Cancel: function () {
|
||||||
|
$(this).dialog("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeLine(line) {
|
||||||
|
const lines = byId("burgGroupsBody").children;
|
||||||
|
if (lines.length < 2) return tip("At least one group should be defined", false, "error");
|
||||||
|
|
||||||
|
confirmationDialog({
|
||||||
|
title: this.dataset.tip,
|
||||||
|
message:
|
||||||
|
"Are you sure you want to remove the group? <br>This WON'T change the burgs unless the changes are applied",
|
||||||
|
confirm: "Remove",
|
||||||
|
onConfirm: () => {
|
||||||
|
line.remove();
|
||||||
|
validateForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function validateForm() {
|
function validateForm() {
|
||||||
const form = byId("burgGroupsForm");
|
const form = byId("burgGroupsForm");
|
||||||
|
|
||||||
|
|
@ -116,6 +278,13 @@ function editBurgGroups() {
|
||||||
|
|
||||||
function parseInput(input) {
|
function parseInput(input) {
|
||||||
if (input.name === "name") return sanitizeId(input.value);
|
if (input.name === "name") return sanitizeId(input.value);
|
||||||
|
if (input.name === "features") {
|
||||||
|
const isValid = JSON.isValid(input.value);
|
||||||
|
const parsed = isValid ? JSON.parse(input.value) : {};
|
||||||
|
if (Object.keys(parsed).length) return parsed;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (input.type === "hidden") return input.value || null;
|
||||||
if (input.type === "radio") return input.checked;
|
if (input.type === "radio") return input.checked;
|
||||||
if (input.type === "checkbox") return input.checked;
|
if (input.type === "checkbox") return input.checked;
|
||||||
if (input.type === "number") {
|
if (input.type === "number") {
|
||||||
|
|
@ -123,7 +292,7 @@ function editBurgGroups() {
|
||||||
if (value === 0 || isNaN(value)) return null;
|
if (value === 0 || isNaN(value)) return null;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return input.value;
|
return input.value || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.burgs.groups = lines.map(line => {
|
options.burgs.groups = lines.map(line => {
|
||||||
|
|
|
||||||
|
|
@ -238,8 +238,8 @@ function editHeightmap(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Biomes.define();
|
Biomes.define();
|
||||||
rankCells();
|
|
||||||
|
|
||||||
|
rankCells();
|
||||||
Cultures.generate();
|
Cultures.generate();
|
||||||
Cultures.expand();
|
Cultures.expand();
|
||||||
|
|
||||||
|
|
@ -247,10 +247,13 @@ function editHeightmap(options) {
|
||||||
States.generate();
|
States.generate();
|
||||||
Routes.generate();
|
Routes.generate();
|
||||||
Religions.generate();
|
Religions.generate();
|
||||||
|
|
||||||
|
Burgs.specify();
|
||||||
|
States.collectStatistics();
|
||||||
States.defineStateForms();
|
States.defineStateForms();
|
||||||
|
|
||||||
Provinces.generate();
|
Provinces.generate();
|
||||||
Provinces.getPoles();
|
Provinces.getPoles();
|
||||||
Burgs.specify();
|
|
||||||
|
|
||||||
Rivers.specify();
|
Rivers.specify();
|
||||||
Features.specify();
|
Features.specify();
|
||||||
|
|
|
||||||
|
|
@ -368,14 +368,17 @@ function overviewMilitary() {
|
||||||
|
|
||||||
const filtered = data.filter(datum => datum.i && !datum.removed);
|
const filtered = data.filter(datum => datum.i && !datum.removed);
|
||||||
const lines = filtered.map(
|
const lines = filtered.map(
|
||||||
({i, name, fullName, color}) =>
|
({i, name, fullName, color}) => /* html */ `
|
||||||
`<tr data-tip="${name}"><td><span style="color:${color}">⬤</span></td>
|
<tr data-tip="${name}">
|
||||||
<td><input data-i="${i}" id="el${i}" type="checkbox" class="checkbox" ${
|
<td><span style="color:${color}">⬤</span></td>
|
||||||
!initial.length || initial.includes(i) ? "checked" : ""
|
<td>
|
||||||
} >
|
<input data-i="${i}" id="el${i}" type="checkbox" class="checkbox"
|
||||||
<label for="el${i}" class="checkbox-label">${fullName || name}</label>
|
${!initial.length || initial.includes(i) ? "checked" : ""} >
|
||||||
</td></tr>`
|
<label for="el${i}" class="checkbox-label">${fullName || name}</label>
|
||||||
|
</td>
|
||||||
|
</tr>`
|
||||||
);
|
);
|
||||||
|
|
||||||
alertMessage.innerHTML = /* html */ `<b>Limit unit by ${type}:</b>
|
alertMessage.innerHTML = /* html */ `<b>Limit unit by ${type}:</b>
|
||||||
<table style="margin-top:.3em">
|
<table style="margin-top:.3em">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -385,7 +388,7 @@ function overviewMilitary() {
|
||||||
|
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
width: fitContent(),
|
width: fitContent(),
|
||||||
title: `Limit unit`,
|
title: "Limit unit",
|
||||||
buttons: {
|
buttons: {
|
||||||
Invert: function () {
|
Invert: function () {
|
||||||
alertMessage.querySelectorAll("input").forEach(el => (el.checked = !el.checked));
|
alertMessage.querySelectorAll("input").forEach(el => (el.checked = !el.checked));
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ function editProvinces() {
|
||||||
layerIsOn("toggleStates") ? drawStates() : toggleStates();
|
layerIsOn("toggleStates") ? drawStates() : toggleStates();
|
||||||
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
|
layerIsOn("toggleBorders") ? drawBorders() : toggleBorders();
|
||||||
|
|
||||||
|
States.findNeighbors();
|
||||||
States.collectStatistics();
|
States.collectStatistics();
|
||||||
States.defineStateForms(newStates);
|
States.defineStateForms(newStates);
|
||||||
drawStateLabels(allStates);
|
drawStateLabels(allStates);
|
||||||
|
|
|
||||||
|
|
@ -155,13 +155,15 @@ function regenerateStates() {
|
||||||
|
|
||||||
pack.states = newStates;
|
pack.states = newStates;
|
||||||
States.expandStates();
|
States.expandStates();
|
||||||
States.normalizeStates();
|
States.normalize();
|
||||||
States.getPoles();
|
States.getPoles();
|
||||||
|
States.findNeighbors();
|
||||||
States.collectStatistics();
|
States.collectStatistics();
|
||||||
States.assignColors();
|
States.assignColors();
|
||||||
States.generateCampaigns();
|
States.generateCampaigns();
|
||||||
States.generateDiplomacy();
|
States.generateDiplomacy();
|
||||||
States.defineStateForms();
|
States.defineStateForms();
|
||||||
|
|
||||||
Provinces.generate(true);
|
Provinces.generate(true);
|
||||||
Provinces.getPoles();
|
Provinces.getPoles();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,10 @@ function parseTransform(string) {
|
||||||
JSON.isValid = str => {
|
JSON.isValid = str => {
|
||||||
try {
|
try {
|
||||||
JSON.parse(str);
|
JSON.parse(str);
|
||||||
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function sanitizeId(string) {
|
function sanitizeId(string) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue