mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-23 20:41:23 +01:00
merge completed... now to fix all the bugs...
This commit is contained in:
commit
87c4d80fbc
3472 changed files with 466748 additions and 6517 deletions
|
|
@ -1,16 +1,15 @@
|
|||
"use strict";
|
||||
'use strict';
|
||||
|
||||
window.Military = (function () {
|
||||
const generate = function () {
|
||||
TIME && console.time("generateMilitaryForces");
|
||||
const cells = pack.cells,
|
||||
p = cells.p,
|
||||
states = pack.states;
|
||||
const valid = states.filter(s => s.i && !s.removed); // valid states
|
||||
TIME && console.time('generateMilitaryForces');
|
||||
const {cells, states} = pack;
|
||||
const {p} = cells;
|
||||
const valid = states.filter((s) => s.i && !s.removed); // valid states
|
||||
if (!options.military) options.military = getDefaultOptions();
|
||||
|
||||
const expn = d3.sum(valid.map(s => s.expansionism)); // total expansion
|
||||
const area = d3.sum(valid.map(s => s.area)); // total area
|
||||
const expn = d3.sum(valid.map((s) => s.expansionism)); // total expansion
|
||||
const area = d3.sum(valid.map((s) => s.area)); // total area
|
||||
const rate = {x: 0, Ally: -0.2, Friendly: -0.1, Neutral: 0, Suspicion: 0.1, Enemy: 1, Unknown: 0, Rival: 0.5, Vassal: 0.5, Suzerain: -0.5};
|
||||
|
||||
const stateModifier = {
|
||||
|
|
@ -19,7 +18,6 @@ window.Military = (function () {
|
|||
mounted: {Nomadic: 2.3, Highland: 0.6, Lake: 0.7, Naval: 0.3, Hunting: 0.7, River: 0.8},
|
||||
machinery: {Nomadic: 0.8, Highland: 1.4, Lake: 1.1, Naval: 1.4, Hunting: 0.4, River: 1.1},
|
||||
naval: {Nomadic: 0.5, Highland: 0.5, Lake: 1.2, Naval: 1.8, Hunting: 0.7, River: 1.2},
|
||||
// non-default generic:
|
||||
armored: {Nomadic: 1, Highland: 0.5, Lake: 1, Naval: 1, Hunting: 0.7, River: 1.1},
|
||||
aviation: {Nomadic: 0.5, Highland: 0.5, Lake: 1.2, Naval: 1.2, Hunting: 0.6, River: 1.2},
|
||||
magical: {Nomadic: 1, Highland: 2, Lake: 1, Naval: 1, Hunting: 1, River: 1}
|
||||
|
|
@ -37,114 +35,136 @@ window.Military = (function () {
|
|||
highland: {melee: 1.2, ranged: 2, mounted: 0.3, machinery: 3, naval: 1.0, armored: 0.8, aviation: 0.3, magical: 2}
|
||||
};
|
||||
|
||||
valid.forEach(s => {
|
||||
const temp = (s.temp = {}),
|
||||
d = s.diplomacy;
|
||||
const expansionRate = Math.min(Math.max(s.expansionism / expn / (s.area / area), 0.25), 4); // how much state expansionism is realized
|
||||
const diplomacyRate = d.some(d => d === "Enemy") ? 1 : d.some(d => d === "Rival") ? 0.8 : d.some(d => d === "Suspicion") ? 0.5 : 0.1; // peacefulness
|
||||
const neighborsRate = Math.min(
|
||||
Math.max(
|
||||
s.neighbors.map(n => (n ? pack.states[n].diplomacy[s.i] : "Suspicion")).reduce((s, r) => (s += rate[r]), 0.5),
|
||||
0.3
|
||||
),
|
||||
3
|
||||
); // neighbors rate
|
||||
s.alert = Math.min(Math.max(rn(expansionRate * diplomacyRate * neighborsRate, 2), 0.1), 5); // war alert rate (army modifier)
|
||||
temp.platoons = [];
|
||||
valid.forEach((s) => {
|
||||
s.temp = {};
|
||||
const d = s.diplomacy;
|
||||
|
||||
const expansionRate = minmax(s.expansionism / expn / (s.area / area), 0.25, 4); // how much state expansionism is realized
|
||||
const diplomacyRate = d.some((d) => d === 'Enemy') ? 1 : d.some((d) => d === 'Rival') ? 0.8 : d.some((d) => d === 'Suspicion') ? 0.5 : 0.1; // peacefulness
|
||||
const neighborsRateRaw = s.neighbors.map((n) => (n ? pack.states[n].diplomacy[s.i] : 'Suspicion')).reduce((s, r) => (s += rate[r]), 0.5);
|
||||
const neighborsRate = minmax(neighborsRateRaw, 0.3, 3); // neighbors rate
|
||||
s.alert = minmax(rn(expansionRate * diplomacyRate * neighborsRate, 2), 0.1, 5); // alert rate (area modifier)
|
||||
s.temp.platoons = [];
|
||||
|
||||
// apply overall state modifiers for unit types based on state features
|
||||
for (const unit of options.military) {
|
||||
if (!stateModifier[unit.type]) continue;
|
||||
|
||||
let modifier = stateModifier[unit.type][s.type] || 1;
|
||||
if (unit.type === "mounted" && s.formName.includes("Horde")) modifier *= 2;
|
||||
else if (unit.type === "naval" && s.form === "Republic") modifier *= 1.2;
|
||||
temp[unit.name] = modifier * s.alert;
|
||||
if (unit.type === 'mounted' && s.formName.includes('Horde')) modifier *= 2;
|
||||
else if (unit.type === 'naval' && s.form === 'Republic') modifier *= 1.2;
|
||||
s.temp[unit.name] = modifier * s.alert;
|
||||
}
|
||||
});
|
||||
|
||||
const getType = cell => {
|
||||
if ([1, 2, 3, 4].includes(cells.biome[cell])) return "nomadic";
|
||||
if ([7, 8, 9, 12].includes(cells.biome[cell])) return "wetland";
|
||||
if (cells.h[cell] >= 70) return "highland";
|
||||
return "generic";
|
||||
const getType = (cell) => {
|
||||
if ([1, 2, 3, 4].includes(cells.biome[cell])) return 'nomadic';
|
||||
if ([7, 8, 9, 12].includes(cells.biome[cell])) return 'wetland';
|
||||
if (cells.h[cell] >= 70) return 'highland';
|
||||
return 'generic';
|
||||
};
|
||||
|
||||
function passUnitLimits(unit, biome, state, culture, religion) {
|
||||
if (unit.biomes && !unit.biomes.includes(biome)) return false;
|
||||
if (unit.states && !unit.states.includes(state)) return false;
|
||||
if (unit.cultures && !unit.cultures.includes(culture)) return false;
|
||||
if (unit.religions && !unit.religions.includes(religion)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const i of cells.i) {
|
||||
if (!cells.pop[i]) continue;
|
||||
const s = states[cells.state[i]]; // cell state
|
||||
if (!s.i || s.removed) continue;
|
||||
|
||||
let m = cells.pop[i] / 100; // basic rural army in percentages
|
||||
if (cells.culture[i] !== s.culture) m = s.form === "Union" ? m / 1.2 : m / 2; // non-dominant culture
|
||||
if (cells.religion[i] !== cells.religion[s.center]) m = s.form === "Theocracy" ? m / 2.2 : m / 1.4; // non-dominant religion
|
||||
if (cells.f[i] !== cells.f[s.center]) m = s.type === "Naval" ? m / 1.2 : m / 1.8; // different landmass
|
||||
const biome = cells.biome[i];
|
||||
const state = cells.state[i];
|
||||
const culture = cells.culture[i];
|
||||
const religion = cells.religion[i];
|
||||
|
||||
const stateObj = states[state];
|
||||
if (!state || stateObj.removed) continue;
|
||||
|
||||
let modifier = cells.pop[i] / 100; // basic rural army in percentages
|
||||
if (culture !== stateObj.culture) modifier = stateObj.form === 'Union' ? modifier / 1.2 : modifier / 2; // non-dominant culture
|
||||
if (religion !== cells.religion[stateObj.center]) modifier = stateObj.form === 'Theocracy' ? modifier / 2.2 : modifier / 1.4; // non-dominant religion
|
||||
if (cells.f[i] !== cells.f[stateObj.center]) modifier = stateObj.type === 'Naval' ? modifier / 1.2 : modifier / 1.8; // different landmass
|
||||
const type = getType(i);
|
||||
|
||||
for (const u of options.military) {
|
||||
const perc = +u.rural;
|
||||
if (isNaN(perc) || perc <= 0 || !s.temp[u.name]) continue;
|
||||
for (const unit of options.military) {
|
||||
const perc = +unit.rural;
|
||||
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
|
||||
if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
|
||||
|
||||
const mod = type === "generic" ? 1 : cellTypeModifier[type][u.type]; // cell specific modifier
|
||||
const army = m * perc * mod; // rural cell army
|
||||
const t = rn(army * s.temp[u.name] * populationRate); // total troops
|
||||
if (!t) continue;
|
||||
let x = p[i][0],
|
||||
y = p[i][1],
|
||||
n = 0;
|
||||
if (u.type === "naval") {
|
||||
const cellTypeMod = type === 'generic' ? 1 : cellTypeModifier[type][unit.type]; // cell specific modifier
|
||||
const army = modifier * perc * cellTypeMod; // rural cell army
|
||||
const total = rn(army * stateObj.temp[unit.name] * populationRate); // total troops
|
||||
if (!total) continue;
|
||||
|
||||
let [x, y] = p[i];
|
||||
let n = 0;
|
||||
|
||||
if (unit.type === 'naval') {
|
||||
let haven = cells.haven[i];
|
||||
(x = p[haven][0]), (y = p[haven][1]);
|
||||
[x, y] = p[haven];
|
||||
n = 1;
|
||||
} // place naval to sea
|
||||
s.temp.platoons.push({cell: i, a: t, t, x, y, u: u.name, n, s: u.separate, type: u.type});
|
||||
|
||||
stateObj.temp.platoons.push({cell: i, a: total, t: total, x, y, u: unit.name, n, s: unit.separate, type: unit.type});
|
||||
}
|
||||
}
|
||||
|
||||
for (const b of pack.burgs) {
|
||||
if (!b.i || b.removed || !b.state || !b.population) continue;
|
||||
const s = states[b.state]; // burg state
|
||||
|
||||
const biome = cells.biome[b.cell];
|
||||
const state = b.state;
|
||||
const culture = b.culture;
|
||||
const religion = cells.religion[b.cell];
|
||||
|
||||
const stateObj = states[state];
|
||||
let m = (b.population * urbanization) / 100; // basic urban army in percentages
|
||||
if (b.capital) m *= 1.2; // capital has household troops
|
||||
if (b.culture !== s.culture) m = s.form === "Union" ? m / 1.2 : m / 2; // non-dominant culture
|
||||
if (cells.religion[b.cell] !== cells.religion[s.center]) m = s.form === "Theocracy" ? m / 2.2 : m / 1.4; // non-dominant religion
|
||||
if (cells.f[b.cell] !== cells.f[s.center]) m = s.type === "Naval" ? m / 1.2 : m / 1.8; // different landmass
|
||||
if (culture !== stateObj.culture) m = stateObj.form === 'Union' ? m / 1.2 : m / 2; // non-dominant culture
|
||||
if (religion !== cells.religion[stateObj.center]) m = stateObj.form === 'Theocracy' ? m / 2.2 : m / 1.4; // non-dominant religion
|
||||
if (cells.f[b.cell] !== cells.f[stateObj.center]) m = stateObj.type === 'Naval' ? m / 1.2 : m / 1.8; // different landmass
|
||||
const type = getType(b.cell);
|
||||
|
||||
for (const u of options.military) {
|
||||
if (u.type === "naval" && !b.port) continue; // only ports produce naval units
|
||||
const perc = +u.urban;
|
||||
if (isNaN(perc) || perc <= 0 || !s.temp[u.name]) continue;
|
||||
for (const unit of options.military) {
|
||||
if (unit.type === 'naval' && !b.port) continue; // only ports produce naval units
|
||||
const perc = +unit.urban;
|
||||
if (isNaN(perc) || perc <= 0 || !stateObj.temp[unit.name]) continue;
|
||||
if (!passUnitLimits(unit, biome, state, culture, religion)) continue;
|
||||
|
||||
const mod = type === "generic" ? 1 : burgTypeModifier[type][u.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 t = rn(army * s.temp[u.name] * populationRate); // total troops
|
||||
if (!t) continue;
|
||||
let x = p[b.cell][0],
|
||||
y = p[b.cell][1],
|
||||
n = 0;
|
||||
if (u.type === "naval") {
|
||||
const total = rn(army * stateObj.temp[unit.name] * populationRate); // total troops
|
||||
if (!total) continue;
|
||||
|
||||
let [x, y] = p[b.cell];
|
||||
let n = 0;
|
||||
|
||||
if (unit.type === 'naval') {
|
||||
let haven = cells.haven[b.cell];
|
||||
(x = p[haven][0]), (y = p[haven][1]);
|
||||
[x, y] = p[haven];
|
||||
n = 1;
|
||||
} // place naval in sea cell
|
||||
s.temp.platoons.push({cell: b.cell, a: t, t, x, y, u: u.name, n, s: u.separate, type: u.type});
|
||||
} // 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});
|
||||
}
|
||||
}
|
||||
|
||||
void (function removeExistingRegiments() {
|
||||
armies.selectAll("g > g").each(function () {
|
||||
const index = notes.findIndex(n => n.id === this.id);
|
||||
armies.selectAll('g > g').each(function () {
|
||||
const index = notes.findIndex((n) => n.id === this.id);
|
||||
if (index != -1) notes.splice(index, 1);
|
||||
});
|
||||
armies.selectAll("g").remove();
|
||||
armies.selectAll('g').remove();
|
||||
})();
|
||||
|
||||
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
|
||||
|
||||
// get regiments for each state
|
||||
valid.forEach(s => {
|
||||
valid.forEach((s) => {
|
||||
s.military = createRegiments(s.temp.platoons, s);
|
||||
delete s.temp; // do not store temp data
|
||||
drawRegiments(s.military, s.i);
|
||||
|
|
@ -155,10 +175,10 @@ window.Military = (function () {
|
|||
nodes.sort((a, b) => a.a - b.a); // form regiments in cells with most troops
|
||||
const tree = d3.quadtree(
|
||||
nodes,
|
||||
d => d.x,
|
||||
d => d.y
|
||||
(d) => d.x,
|
||||
(d) => d.y
|
||||
);
|
||||
nodes.forEach(n => {
|
||||
nodes.forEach((n) => {
|
||||
tree.remove(n);
|
||||
const overlap = tree.find(n.x, n.y, 20);
|
||||
if (overlap && overlap.t && mergeable(n, overlap)) {
|
||||
|
|
@ -180,24 +200,24 @@ window.Military = (function () {
|
|||
function merge(n0, n1) {
|
||||
if (!n1.childen) n1.childen = [n0];
|
||||
else n1.childen.push(n0);
|
||||
if (n0.childen) n0.childen.forEach(n => n1.childen.push(n));
|
||||
if (n0.childen) n0.childen.forEach((n) => n1.childen.push(n));
|
||||
n1.t += n0.t;
|
||||
n0.t = 0;
|
||||
}
|
||||
|
||||
// parse regiments data
|
||||
const regiments = nodes
|
||||
.filter(n => n.t)
|
||||
.filter((n) => n.t)
|
||||
.sort((a, b) => b.t - a.t)
|
||||
.map((r, i) => {
|
||||
const u = {};
|
||||
u[r.u] = r.a;
|
||||
(r.childen || []).forEach(n => (u[n.u] = u[n.u] ? (u[n.u] += n.a) : n.a));
|
||||
(r.childen || []).forEach((n) => (u[n.u] = u[n.u] ? (u[n.u] += n.a) : n.a));
|
||||
return {i, a: r.t, cell: r.cell, x: r.x, y: r.y, bx: r.x, by: r.y, u, n: r.n, name, state: s.i};
|
||||
});
|
||||
|
||||
// generate name for regiments
|
||||
regiments.forEach(r => {
|
||||
regiments.forEach((r) => {
|
||||
r.name = getName(r, regiments);
|
||||
r.icon = getEmblem(r);
|
||||
generateNote(r, s);
|
||||
|
|
@ -206,164 +226,175 @@ window.Military = (function () {
|
|||
return regiments;
|
||||
}
|
||||
|
||||
TIME && console.timeEnd("generateMilitaryForces");
|
||||
TIME && console.timeEnd('generateMilitaryForces');
|
||||
};
|
||||
|
||||
const getDefaultOptions = function () {
|
||||
return [
|
||||
{icon: "⚔️", name: "infantry", rural: 0.25, urban: 0.2, crew: 1, power: 1, type: "melee", separate: 0},
|
||||
{icon: "🏹", name: "archers", rural: 0.12, urban: 0.2, crew: 1, power: 1, type: "ranged", separate: 0},
|
||||
{icon: "🐴", name: "cavalry", rural: 0.12, urban: 0.03, crew: 2, power: 2, type: "mounted", separate: 0},
|
||||
{icon: "💣", name: "artillery", rural: 0, urban: 0.03, crew: 8, power: 12, type: "machinery", separate: 0},
|
||||
{icon: "🌊", name: "fleet", rural: 0, urban: 0.015, crew: 100, power: 50, type: "naval", separate: 1}
|
||||
{icon: '⚔️', name: 'infantry', rural: 0.25, urban: 0.2, crew: 1, power: 1, type: 'melee', separate: 0},
|
||||
{icon: '🏹', name: 'archers', rural: 0.12, urban: 0.2, crew: 1, power: 1, type: 'ranged', separate: 0},
|
||||
{icon: '🐴', name: 'cavalry', rural: 0.12, urban: 0.03, crew: 2, power: 2, type: 'mounted', separate: 0},
|
||||
{icon: '💣', name: 'artillery', rural: 0, urban: 0.03, crew: 8, power: 12, type: 'machinery', separate: 0},
|
||||
{icon: '🌊', name: 'fleet', rural: 0, urban: 0.015, crew: 100, power: 50, type: 'naval', separate: 1}
|
||||
];
|
||||
};
|
||||
|
||||
const drawRegiments = function (regiments, s) {
|
||||
const size = +armies.attr("box-size");
|
||||
const w = d => (d.n ? size * 4 : size * 6);
|
||||
const size = +armies.attr('box-size');
|
||||
const w = (d) => (d.n ? size * 4 : size * 6);
|
||||
const h = size * 2;
|
||||
const x = d => rn(d.x - w(d) / 2, 2);
|
||||
const y = d => rn(d.y - size, 2);
|
||||
const x = (d) => rn(d.x - w(d) / 2, 2);
|
||||
const y = (d) => rn(d.y - size, 2);
|
||||
|
||||
const baseColor = pack.states[s].color[0] === "#" ? pack.states[s].color : "#999";
|
||||
const baseColor = pack.states[s].color[0] === '#' ? pack.states[s].color : '#999';
|
||||
const darkerColor = d3.color(baseColor).darker().hex();
|
||||
const army = armies
|
||||
.append("g")
|
||||
.attr("id", "army" + s)
|
||||
.attr("fill", baseColor);
|
||||
.append('g')
|
||||
.attr('id', 'army' + s)
|
||||
.attr('fill', baseColor);
|
||||
|
||||
const g = army
|
||||
.selectAll("g")
|
||||
.selectAll('g')
|
||||
.data(regiments)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("id", d => "regiment" + s + "-" + d.i)
|
||||
.attr("data-name", d => d.name)
|
||||
.attr("data-state", s)
|
||||
.attr("data-id", d => d.i);
|
||||
g.append("rect")
|
||||
.attr("x", d => x(d))
|
||||
.attr("y", d => y(d))
|
||||
.attr("width", d => w(d))
|
||||
.attr("height", h);
|
||||
g.append("text")
|
||||
.attr("x", d => d.x)
|
||||
.attr("y", d => d.y)
|
||||
.text(d => getTotal(d));
|
||||
g.append("rect")
|
||||
.attr("fill", darkerColor)
|
||||
.attr("x", d => x(d) - h)
|
||||
.attr("y", d => y(d))
|
||||
.attr("width", h)
|
||||
.attr("height", h);
|
||||
g.append("text")
|
||||
.attr("class", "regimentIcon")
|
||||
.attr("x", d => x(d) - size)
|
||||
.attr("y", d => d.y)
|
||||
.text(d => d.icon);
|
||||
.append('g')
|
||||
.attr('id', (d) => 'regiment' + s + '-' + d.i)
|
||||
.attr('data-name', (d) => d.name)
|
||||
.attr('data-state', s)
|
||||
.attr('data-id', (d) => d.i);
|
||||
g.append('rect')
|
||||
.attr('x', (d) => x(d))
|
||||
.attr('y', (d) => y(d))
|
||||
.attr('width', (d) => w(d))
|
||||
.attr('height', h);
|
||||
g.append('text')
|
||||
.attr('x', (d) => d.x)
|
||||
.attr('y', (d) => d.y)
|
||||
.text((d) => getTotal(d));
|
||||
g.append('rect')
|
||||
.attr('fill', darkerColor)
|
||||
.attr('x', (d) => x(d) - h)
|
||||
.attr('y', (d) => y(d))
|
||||
.attr('width', h)
|
||||
.attr('height', h);
|
||||
g.append('text')
|
||||
.attr('class', 'regimentIcon')
|
||||
.attr('x', (d) => x(d) - size)
|
||||
.attr('y', (d) => d.y)
|
||||
.text((d) => d.icon);
|
||||
};
|
||||
|
||||
const drawRegiment = function (reg, s) {
|
||||
const size = +armies.attr("box-size");
|
||||
const size = +armies.attr('box-size');
|
||||
const w = reg.n ? size * 4 : size * 6;
|
||||
const h = size * 2;
|
||||
const x1 = rn(reg.x - w / 2, 2);
|
||||
const y1 = rn(reg.y - size, 2);
|
||||
|
||||
let army = armies.select("g#army" + s);
|
||||
let army = armies.select('g#army' + s);
|
||||
if (!army.size()) {
|
||||
const baseColor = pack.states[s].color[0] === "#" ? pack.states[s].color : "#999";
|
||||
const baseColor = pack.states[s].color[0] === '#' ? pack.states[s].color : '#999';
|
||||
army = armies
|
||||
.append("g")
|
||||
.attr("id", "army" + s)
|
||||
.attr("fill", baseColor);
|
||||
.append('g')
|
||||
.attr('id', 'army' + s)
|
||||
.attr('fill', baseColor);
|
||||
}
|
||||
const darkerColor = d3.color(army.attr("fill")).darker().hex();
|
||||
const darkerColor = d3.color(army.attr('fill')).darker().hex();
|
||||
|
||||
const g = army
|
||||
.append("g")
|
||||
.attr("id", "regiment" + s + "-" + reg.i)
|
||||
.attr("data-name", reg.name)
|
||||
.attr("data-state", s)
|
||||
.attr("data-id", reg.i);
|
||||
g.append("rect").attr("x", x1).attr("y", y1).attr("width", w).attr("height", h);
|
||||
g.append("text").attr("x", reg.x).attr("y", reg.y).text(getTotal(reg));
|
||||
g.append("rect")
|
||||
.attr("fill", darkerColor)
|
||||
.attr("x", x1 - h)
|
||||
.attr("y", y1)
|
||||
.attr("width", h)
|
||||
.attr("height", h);
|
||||
g.append("text")
|
||||
.attr("class", "regimentIcon")
|
||||
.attr("x", x1 - size)
|
||||
.attr("y", reg.y)
|
||||
.append('g')
|
||||
.attr('id', 'regiment' + s + '-' + reg.i)
|
||||
.attr('data-name', reg.name)
|
||||
.attr('data-state', s)
|
||||
.attr('data-id', reg.i);
|
||||
g.append('rect').attr('x', x1).attr('y', y1).attr('width', w).attr('height', h);
|
||||
g.append('text').attr('x', reg.x).attr('y', reg.y).text(getTotal(reg));
|
||||
g.append('rect')
|
||||
.attr('fill', darkerColor)
|
||||
.attr('x', x1 - h)
|
||||
.attr('y', y1)
|
||||
.attr('width', h)
|
||||
.attr('height', h);
|
||||
g.append('text')
|
||||
.attr('class', 'regimentIcon')
|
||||
.attr('x', x1 - size)
|
||||
.attr('y', reg.y)
|
||||
.text(reg.icon);
|
||||
};
|
||||
|
||||
// move one regiment to another
|
||||
const moveRegiment = function (reg, x, y) {
|
||||
const el = armies.select("g#army" + reg.state).select("g#regiment" + reg.state + "-" + reg.i);
|
||||
const el = armies.select('g#army' + reg.state).select('g#regiment' + reg.state + '-' + reg.i);
|
||||
if (!el.size()) return;
|
||||
|
||||
const duration = Math.hypot(reg.x - x, reg.y - y) * 8;
|
||||
reg.x = x;
|
||||
reg.y = y;
|
||||
const size = +armies.attr("box-size");
|
||||
const size = +armies.attr('box-size');
|
||||
const w = reg.n ? size * 4 : size * 6;
|
||||
const h = size * 2;
|
||||
const x1 = x => rn(x - w / 2, 2);
|
||||
const y1 = y => rn(y - size, 2);
|
||||
const x1 = (x) => rn(x - w / 2, 2);
|
||||
const y1 = (y) => rn(y - size, 2);
|
||||
|
||||
const move = d3.transition().duration(duration).ease(d3.easeSinInOut);
|
||||
el.select("rect").transition(move).attr("x", x1(x)).attr("y", y1(y));
|
||||
el.select("text").transition(move).attr("x", x).attr("y", y);
|
||||
el.selectAll("rect:nth-of-type(2)")
|
||||
el.select('rect').transition(move).attr('x', x1(x)).attr('y', y1(y));
|
||||
el.select('text').transition(move).attr('x', x).attr('y', y);
|
||||
el.selectAll('rect:nth-of-type(2)')
|
||||
.transition(move)
|
||||
.attr("x", x1(x) - h)
|
||||
.attr("y", y1(y));
|
||||
el.select(".regimentIcon")
|
||||
.attr('x', x1(x) - h)
|
||||
.attr('y', y1(y));
|
||||
el.select('.regimentIcon')
|
||||
.transition(move)
|
||||
.attr("x", x1(x) - size)
|
||||
.attr("y", y);
|
||||
.attr('x', x1(x) - size)
|
||||
.attr('y', y);
|
||||
};
|
||||
|
||||
// utilize si function to make regiment total text fit regiment box
|
||||
const getTotal = reg => (reg.a > (reg.n ? 999 : 99999) ? si(reg.a) : reg.a);
|
||||
const getTotal = (reg) => (reg.a > (reg.n ? 999 : 99999) ? si(reg.a) : reg.a);
|
||||
|
||||
const getName = function (r, regiments) {
|
||||
const cells = pack.cells;
|
||||
const proper = r.n ? null : cells.province[r.cell] && pack.provinces[cells.province[r.cell]] ? pack.provinces[cells.province[r.cell]].name : cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]] ? pack.burgs[cells.burg[r.cell]].name : null;
|
||||
const number = nth(regiments.filter(reg => reg.n === r.n && reg.i < r.i).length + 1);
|
||||
const form = r.n ? "Fleet" : "Regiment";
|
||||
const proper = r.n
|
||||
? null
|
||||
: cells.province[r.cell] && pack.provinces[cells.province[r.cell]]
|
||||
? pack.provinces[cells.province[r.cell]].name
|
||||
: cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]]
|
||||
? pack.burgs[cells.burg[r.cell]].name
|
||||
: null;
|
||||
const number = nth(regiments.filter((reg) => reg.n === r.n && reg.i < r.i).length + 1);
|
||||
const form = r.n ? 'Fleet' : 'Regiment';
|
||||
return `${number}${proper ? ` (${proper}) ` : ` `}${form}`;
|
||||
};
|
||||
|
||||
// get default regiment emblem
|
||||
const getEmblem = function (r) {
|
||||
if (!r.n && !Object.values(r.u).length) return "🔰"; // "Newbie" regiment without troops
|
||||
if (!r.n && pack.states[r.state].form === "Monarchy" && pack.cells.burg[r.cell] && pack.burgs[pack.cells.burg[r.cell]].capital) return "👑"; // "Royal" regiment based in capital
|
||||
if (!r.n && !Object.values(r.u).length) return '🔰'; // "Newbie" regiment without troops
|
||||
if (!r.n && pack.states[r.state].form === 'Monarchy' && pack.cells.burg[r.cell] && pack.burgs[pack.cells.burg[r.cell]].capital) return '👑'; // "Royal" regiment based in capital
|
||||
const mainUnit = Object.entries(r.u).sort((a, b) => b[1] - a[1])[0][0]; // unit with more troops in regiment
|
||||
const unit = options.military.find(u => u.name === mainUnit);
|
||||
const unit = options.military.find((u) => u.name === mainUnit);
|
||||
return unit.icon;
|
||||
};
|
||||
|
||||
const generateNote = function (r, s) {
|
||||
const cells = pack.cells;
|
||||
const base = cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]] ? pack.burgs[cells.burg[r.cell]].name : cells.province[r.cell] && pack.provinces[cells.province[r.cell]] ? pack.provinces[cells.province[r.cell]].fullName : null;
|
||||
const station = base ? `${r.name} is ${r.n ? "based" : "stationed"} in ${base}. ` : "";
|
||||
const base =
|
||||
cells.burg[r.cell] && pack.burgs[cells.burg[r.cell]]
|
||||
? pack.burgs[cells.burg[r.cell]].name
|
||||
: cells.province[r.cell] && pack.provinces[cells.province[r.cell]]
|
||||
? pack.provinces[cells.province[r.cell]].fullName
|
||||
: null;
|
||||
const station = base ? `${r.name} is ${r.n ? 'based' : 'stationed'} in ${base}. ` : '';
|
||||
|
||||
const composition = r.a
|
||||
? Object.keys(r.u)
|
||||
.map(t => `— ${t}: ${r.u[t]}`)
|
||||
.join("\r\n")
|
||||
.map((t) => `— ${t}: ${r.u[t]}`)
|
||||
.join('\r\n')
|
||||
: null;
|
||||
const troops = composition ? `\r\n\r\nRegiment composition in ${options.year} ${options.eraShort}:\r\n${composition}.` : "";
|
||||
const troops = composition ? `\r\n\r\nRegiment composition in ${options.year} ${options.eraShort}:\r\n${composition}.` : '';
|
||||
|
||||
const campaign = s.campaigns ? ra(s.campaigns) : null;
|
||||
const year = campaign ? rand(campaign.start, campaign.end) : gauss(options.year - 100, 150, 1, options.year - 6);
|
||||
const conflict = campaign ? ` during the ${campaign.name}` : "";
|
||||
const conflict = campaign ? ` during the ${campaign.name}` : '';
|
||||
const legend = `Regiment was formed in ${year} ${options.era}${conflict}. ${station}${troops}`;
|
||||
notes.push({id: `regiment${s.i}-${r.i}`, name: `${r.icon} ${r.name}`, legend});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue