military - fix rural fleet

This commit is contained in:
Azgaar 2021-11-10 23:57:27 +03:00
parent 4c95d44faa
commit 00dcf8b80d
2 changed files with 35 additions and 26 deletions

View file

@ -72,6 +72,7 @@ window.Military = (function () {
return true; return true;
} }
// rural cells
for (const i of cells.i) { for (const i of cells.i) {
if (!cells.pop[i]) continue; if (!cells.pop[i]) continue;
@ -93,6 +94,7 @@ window.Military = (function () {
const perc = +unit.rural; const perc = +unit.rural;
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue; if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
if (!passUnitLimits(unit, biome, state, culture, religion)) continue; if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
if (unit.type === "naval" && !cells.haven[i]) continue; // only near-ocean cells create naval units
const cellTypeMod = type === "generic" ? 1 : cellTypeModifier[type][unit.type]; // cell specific modifier const cellTypeMod = type === "generic" ? 1 : cellTypeModifier[type][unit.type]; // cell specific modifier
const army = modifier * perc * cellTypeMod; // rural cell army const army = modifier * perc * cellTypeMod; // rural cell army
@ -102,16 +104,18 @@ window.Military = (function () {
let [x, y] = p[i]; let [x, y] = p[i];
let n = 0; let n = 0;
// place naval units to sea
if (unit.type === "naval") { if (unit.type === "naval") {
let haven = cells.haven[i]; const haven = cells.haven[i];
[x, y] = p[haven]; [x, y] = p[haven];
n = 1; n = 1;
} // place naval to sea }
stateObj.temp.platoons.push({cell: i, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type}); stateObj.temp.platoons.push({cell: i, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type});
} }
} }
// burgs
for (const b of pack.burgs) { for (const b of pack.burgs) {
if (!b.i || b.removed || !b.state || !b.population) continue; if (!b.i || b.removed || !b.state || !b.population) continue;
@ -129,10 +133,10 @@ window.Military = (function () {
const type = getType(b.cell); const type = getType(b.cell);
for (const unit of options.military) { for (const unit of options.military) {
if (unit.type === "naval" && !b.port) continue; // only ports produce naval units
const perc = +unit.urban; const perc = +unit.urban;
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue; if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
if (!passUnitLimits(unit, biome, state, culture, religion)) continue; if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
if (unit.type === "naval" && (!b.port || !cells.haven[b.cell])) continue; // only ports create naval units
const mod = type === "generic" ? 1 : burgTypeModifier[type][unit.type]; // cell specific modifier const mod = type === "generic" ? 1 : burgTypeModifier[type][unit.type]; // cell specific modifier
const army = m * perc * mod; // urban cell army const army = m * perc * mod; // urban cell army
@ -142,11 +146,12 @@ window.Military = (function () {
let [x, y] = p[b.cell]; let [x, y] = p[b.cell];
let n = 0; let n = 0;
// place naval to sea
if (unit.type === "naval") { if (unit.type === "naval") {
let haven = cells.haven[b.cell]; const haven = cells.haven[b.cell];
[x, y] = p[haven]; [x, y] = p[haven];
n = 1; n = 1;
} // place naval to sea }
stateObj.temp.platoons.push({cell: b.cell, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type}); stateObj.temp.platoons.push({cell: b.cell, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type});
} }
@ -161,7 +166,7 @@ window.Military = (function () {
})(); })();
const expected = 3 * populationRate; // expected regiment size const expected = 3 * populationRate; // expected regiment size
const mergeable = (n0, n1) => (!n0.s && !n1.s) || n0.type === n1.type; // check if regiments can be merged const mergeable = (n0, n1) => (!n0.s && !n1.s) || n0.u === n1.u; // check if regiments can be merged
// get regiments for each state // get regiments for each state
valid.forEach(s => { valid.forEach(s => {
@ -172,25 +177,27 @@ window.Military = (function () {
function createRegiments(nodes, s) { function createRegiments(nodes, s) {
if (!nodes.length) return []; if (!nodes.length) return [];
nodes.sort((a, b) => a.a - b.a); // form regiments in cells with most troops nodes.sort((a, b) => a.a - b.a); // form regiments in cells with most troops
const tree = d3.quadtree( const tree = d3.quadtree(
nodes, nodes,
d => d.x, d => d.x,
d => d.y d => d.y
); );
nodes.forEach(n => {
tree.remove(n); nodes.forEach(node => {
const overlap = tree.find(n.x, n.y, 20); tree.remove(node);
if (overlap && overlap.t && mergeable(n, overlap)) { const overlap = tree.find(node.x, node.y, 20);
merge(n, overlap); if (overlap && overlap.t && mergeable(node, overlap)) {
merge(node, overlap);
return; return;
} }
if (n.t > expected) return; if (node.t > expected) return;
const r = (expected - n.t) / (n.s ? 40 : 20); // search radius const r = (expected - node.t) / (node.s ? 40 : 20); // search radius
const candidates = tree.findAll(n.x, n.y, r); const candidates = tree.findAll(node.x, node.y, r);
for (const c of candidates) { for (const c of candidates) {
if (c.t < expected && mergeable(n, c)) { if (c.t < expected && mergeable(node, c)) {
merge(n, c); merge(node, c);
break; break;
} }
} }

View file

@ -280,8 +280,10 @@ function overviewMilitary() {
} }
function addUnitLine(unit) { function addUnitLine(unit) {
const {type, icon, name, rural, urban, power, crew, separate} = unit;
const row = document.createElement("tr"); const row = document.createElement("tr");
const typeOptions = types.map(t => `<option ${unit.type === t ? "selected" : ""} value="${t}">${t}</option>`).join(" "); const typeOptions = types.map(t => `<option ${type === t ? "selected" : ""} value="${t}">${t}</option>`).join(" ");
const getLimitButton = attr => const getLimitButton = attr =>
`<button `<button
data-tip="Select allowed ${attr}" data-tip="Select allowed ${attr}"
@ -291,20 +293,20 @@ function overviewMilitary() {
${getLimitText(unit[attr])} ${getLimitText(unit[attr])}
</button>`; </button>`;
row.innerHTML = `<td><button data-type="icon" data-tip="Click to select unit icon">${unit.icon || " "}</button></td> row.innerHTML = `<td><button data-type="icon" data-tip="Click to select unit icon">${icon || " "}</button></td>
<td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${unit.name}"></td> <td><input data-tip="Type unit name. If name is changed for existing unit, old unit will be replaced" value="${name}"></td>
<td>${getLimitButton("biomes")}</td> <td>${getLimitButton("biomes")}</td>
<td>${getLimitButton("states")}</td> <td>${getLimitButton("states")}</td>
<td>${getLimitButton("cultures")}</td> <td>${getLimitButton("cultures")}</td>
<td>${getLimitButton("religions")}</td> <td>${getLimitButton("religions")}</td>
<td><input data-tip="Enter conscription percentage for rural population" type="number" min=0 max=100 step=.01 value="${unit.rural}"></td> <td><input data-tip="Enter conscription percentage for rural population" type="number" min=0 max=100 step=.01 value="${rural}"></td>
<td><input data-tip="Enter conscription percentage for urban population" type="number" min=0 max=100 step=.01 value="${unit.urban}"></td> <td><input data-tip="Enter conscription percentage for urban population" type="number" min=0 max=100 step=.01 value="${urban}"></td>
<td><input data-tip="Enter average number of people in crew (for total personnel calculation)" type="number" min=1 step=1 value="${unit.crew}"></td> <td><input data-tip="Enter average number of people in crew (for total personnel calculation)" type="number" min=1 step=1 value="${crew}"></td>
<td><input data-tip="Enter military power (used for battle simulation)" type="number" min=0 step=.1 value="${unit.power}"></td> <td><input data-tip="Enter military power (used for battle simulation)" type="number" min=0 step=.1 value="${power}"></td>
<td><select data-tip="Select unit type to apply special rules on forces recalculation">${typeOptions}</select></td> <td><select data-tip="Select unit type to apply special rules on forces recalculation">${typeOptions}</select></td>
<td data-tip="Check if unit is separate and can be stacked only with units of the same type"> <td data-tip="Check if unit is <b>separate</b> and can be stacked only with the same units">
<input id="${unit.name}Separate" type="checkbox" class="checkbox" ${unit.separate ? "checked" : ""}> <input id="${name}Separate" type="checkbox" class="checkbox" ${separate ? "checked" : ""}>
<label for="${unit.name}Separate" class="checkbox-label"></label></td> <label for="${name}Separate" class="checkbox-label"></label></td>
<td data-tip="Remove the unit"><span data-tip="Remove unit type" class="icon-trash-empty pointer" onclick="this.parentElement.parentElement.remove();"></span></td>`; <td data-tip="Remove the unit"><span data-tip="Remove unit type" class="icon-trash-empty pointer" onclick="this.parentElement.parentElement.remove();"></span></td>`;
tableBody.appendChild(row); tableBody.appendChild(row);
} }