mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 12:01:23 +01:00
burgs placement change + resource style
This commit is contained in:
parent
9722470a3d
commit
2df06c1b7e
4 changed files with 107 additions and 82 deletions
29
main.js
29
main.js
|
|
@ -1542,7 +1542,7 @@ function getBiomeId(moisture, temperature, height) {
|
|||
return biomesData.biomesMartix[moistureBand][temperatureBand];
|
||||
}
|
||||
|
||||
// assess cells suitability to calculate population and rand cells for culture center and burgs placement
|
||||
// assess cells suitability to calculate population and rang cells for culture center and burgs placement
|
||||
function rankCells() {
|
||||
TIME && console.time("rankCells");
|
||||
const {cells, features} = pack;
|
||||
|
|
@ -1552,13 +1552,18 @@ function rankCells() {
|
|||
const flMean = d3.median(cells.fl.filter(f => f)) || 0,
|
||||
flMax = d3.max(cells.fl) + d3.max(cells.conf); // to normalize flux
|
||||
const areaMean = d3.mean(cells.area); // to adjust population by cell area
|
||||
const getResValue = (i) => (cells.resource[i] ? Resources.get(cells.resource[i])?.value : 0);
|
||||
const resBonuses = [];
|
||||
const POP_BALANCER = 1.5; // contant to ballance population to desired number not changing ranking
|
||||
|
||||
for (const i of cells.i) {
|
||||
if (cells.b[i]) continue; // avoid adding burgs on map border
|
||||
if (cells.h[i] < 20) continue; // no population in water
|
||||
let s = +biomesData.habitability[cells.biome[i]]; // base suitability derived from biome habitability
|
||||
let s = biomesData.habitability[cells.biome[i]] / 10; // base suitability derived from biome habitability
|
||||
if (!s) continue; // uninhabitable biomes has 0 suitability
|
||||
if (flMean) s += normalize(cells.fl[i] + cells.conf[i], flMean, flMax) * 250; // big rivers and confluences are valued
|
||||
s -= (cells.h[i] - 50) / 5; // low elevation is valued, high is not;
|
||||
|
||||
if (flMean) s += normalize(cells.fl[i] + cells.conf[i], flMean, flMax) * 50; // big rivers and confluences are valued
|
||||
s -= (cells.h[i] - 50) / 25; // low elevation is valued, high is not;
|
||||
|
||||
if (cells.t[i] === 1) {
|
||||
if (cells.r[i]) s += 15; // estuary is valued
|
||||
|
|
@ -1571,14 +1576,22 @@ function rankCells() {
|
|||
else if (feature.group == "sinkhole") s -= 5;
|
||||
else if (feature.group == "lava") s -= 30;
|
||||
} else {
|
||||
s += 5; // ocean coast is valued
|
||||
if (cells.harbor[i] === 1) s += 20; // safe sea harbor is valued
|
||||
s += 1; // ocean coast is valued
|
||||
if (cells.harbor[i] === 1) s += 4; // safe sea harbor is valued
|
||||
}
|
||||
}
|
||||
|
||||
cells.s[i] = s / 5; // general population rate
|
||||
// add bonus for resources around
|
||||
const cellRes = getResValue(i);
|
||||
const neibRes = d3.mean(cells.c[i].map((c) => getResValue(c)));
|
||||
const resBonus = (cellRes ? cellRes + 10 : 0) + neibRes;
|
||||
resBonuses.push(resBonus);
|
||||
|
||||
// cell rural population is suitability adjusted by cell area
|
||||
cells.pop[i] = cells.s[i] > 0 ? (cells.s[i] * cells.area[i]) / areaMean : 0;
|
||||
cells.pop[i] = s > 0 ? (s * POP_BALANCER * cells.area[i]) / areaMean : 0;
|
||||
cells.s[i] = s + resBonus;
|
||||
|
||||
debug.append('text').attr('x', cells.p[i][0]).attr('y', cells.p[i][1]).text(cells.s[i]);
|
||||
}
|
||||
|
||||
TIME && console.timeEnd("rankCells");
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
|
||||
if (i === sorted.length - 1) {
|
||||
WARN && console.warn("Cannot place capitals with current spacing. Trying again with reduced spacing");
|
||||
WARN && console.warn('Cannot place capitals with current spacing. Trying again with reduced spacing');
|
||||
burgsTree = d3.quadtree();
|
||||
i = -1;
|
||||
burgs = [0];
|
||||
|
|
@ -221,10 +221,10 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
|
||||
// de-assign port status if it's the only one on feature
|
||||
const ports = pack.burgs.filter(b => !b.removed && b.port > 0);
|
||||
const ports = pack.burgs.filter((b) => !b.removed && b.port > 0);
|
||||
for (const f of features) {
|
||||
if (!f.i || f.land || f.border) continue;
|
||||
const featurePorts = ports.filter(b => b.port === f.i);
|
||||
const featurePorts = ports.filter((b) => b.port === f.i);
|
||||
if (featurePorts.length === 1) featurePorts[0].port = 0;
|
||||
}
|
||||
|
||||
|
|
@ -233,14 +233,14 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
const getType = function (i, port) {
|
||||
const cells = pack.cells;
|
||||
if (port) return "Naval";
|
||||
if (cells.haven[i] && pack.features[cells.f[cells.haven[i]]].type === "lake") return "Lake";
|
||||
if (cells.h[i] > 60) return "Highland";
|
||||
if (cells.r[i] && cells.r[i].length > 100 && cells.r[i].length >= pack.rivers[0].length) return "River";
|
||||
if (port) return 'Naval';
|
||||
if (cells.haven[i] && pack.features[cells.f[cells.haven[i]]].type === 'lake') return 'Lake';
|
||||
if (cells.h[i] > 60) return 'Highland';
|
||||
if (cells.r[i] && cells.r[i].length > 100 && cells.r[i].length >= pack.rivers[0].length) return 'River';
|
||||
|
||||
if (!cells.burg[i] || pack.burgs[cells.burg[i]].population < 6) {
|
||||
if (population < 5 && [1, 2, 3, 4].includes(cells.biome[i])) return "Nomadic";
|
||||
if (cells.biome[i] > 4 && cells.biome[i] < 10) return "Hunting";
|
||||
if (population < 5 && [1, 2, 3, 4].includes(cells.biome[i])) return 'Nomadic';
|
||||
if (cells.biome[i] > 4 && cells.biome[i] < 10) return 'Hunting';
|
||||
}
|
||||
|
||||
return "Generic";
|
||||
|
|
@ -266,9 +266,9 @@ window.BurgsAndStates = (function () {
|
|||
TIME && console.time("drawBurgs");
|
||||
|
||||
// remove old data
|
||||
burgIcons.selectAll("circle").remove();
|
||||
burgLabels.selectAll("text").remove();
|
||||
icons.selectAll("use").remove();
|
||||
burgIcons.selectAll('circle').remove();
|
||||
burgLabels.selectAll('text').remove();
|
||||
icons.selectAll('use').remove();
|
||||
|
||||
// capitals
|
||||
const capitals = pack.burgs.filter(b => b.capital && !b.removed);
|
||||
|
|
@ -385,7 +385,7 @@ window.BurgsAndStates = (function () {
|
|||
const {e, p, s, b} = next;
|
||||
const {type, culture} = states[s];
|
||||
|
||||
cells.c[e].forEach(e => {
|
||||
cells.c[e].forEach((e) => {
|
||||
if (cells.state[e] && e === states[cells.state[e]].center) return; // do not overwrite capital cells
|
||||
|
||||
const cultureCost = culture === cells.culture[e] ? -9 : 100;
|
||||
|
|
@ -411,33 +411,33 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
function getBiomeCost(b, biome, type) {
|
||||
if (b === biome) return 10; // tiny penalty for native biome
|
||||
if (type === "Hunting") return biomesData.cost[biome] * 2; // non-native biome penalty for hunters
|
||||
if (type === "Nomadic" && biome > 4 && biome < 10) return biomesData.cost[biome] * 3; // forest biome penalty for nomads
|
||||
if (type === 'Hunting') return biomesData.cost[biome] * 2; // non-native biome penalty for hunters
|
||||
if (type === 'Nomadic' && biome > 4 && biome < 10) return biomesData.cost[biome] * 3; // forest biome penalty for nomads
|
||||
return biomesData.cost[biome]; // general non-native biome penalty
|
||||
}
|
||||
|
||||
function getHeightCost(f, h, type) {
|
||||
if (type === "Lake" && f.type === "lake") return 10; // low lake crossing penalty for Lake cultures
|
||||
if (type === "Naval" && h < 20) return 300; // low sea crossing penalty for Navals
|
||||
if (type === "Nomadic" && h < 20) return 10000; // giant sea crossing penalty for Nomads
|
||||
if (type === 'Lake' && f.type === 'lake') return 10; // low lake crossing penalty for Lake cultures
|
||||
if (type === 'Naval' && h < 20) return 300; // low sea crossing penalty for Navals
|
||||
if (type === 'Nomadic' && h < 20) return 10000; // giant sea crossing penalty for Nomads
|
||||
if (h < 20) return 1000; // general sea crossing penalty
|
||||
if (type === "Highland" && h < 62) return 1100; // penalty for highlanders on lowlands
|
||||
if (type === "Highland") return 0; // no penalty for highlanders on highlands
|
||||
if (type === 'Highland' && h < 62) return 1100; // penalty for highlanders on lowlands
|
||||
if (type === 'Highland') return 0; // no penalty for highlanders on highlands
|
||||
if (h >= 67) return 2200; // general mountains crossing penalty
|
||||
if (h >= 44) return 300; // general hills crossing penalty
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getRiverCost(r, i, type) {
|
||||
if (type === "River") return r ? 0 : 100; // penalty for river cultures
|
||||
if (type === 'River') return r ? 0 : 100; // penalty for river cultures
|
||||
if (!r) return 0; // no penalty for others if there is no river
|
||||
return minmax(cells.fl[i] / 10, 20, 100); // river penalty from 20 to 100 based on flux
|
||||
}
|
||||
|
||||
function getTypeCost(t, type) {
|
||||
if (t === 1) return type === "Naval" || type === "Lake" ? 0 : type === "Nomadic" ? 60 : 20; // penalty for coastline
|
||||
if (t === 2) return type === "Naval" || type === "Nomadic" ? 30 : 0; // low penalty for land level 2 for Navals and nomads
|
||||
if (t !== -1) return type === "Naval" || type === "Lake" ? 100 : 0; // penalty for mainland for navals
|
||||
if (t === 1) return type === 'Naval' || type === 'Lake' ? 0 : type === 'Nomadic' ? 60 : 20; // penalty for coastline
|
||||
if (t === 2) return type === 'Naval' || type === 'Nomadic' ? 30 : 0; // low penalty for land level 2 for Navals and nomads
|
||||
if (t !== -1) return type === 'Naval' || type === 'Lake' ? 100 : 0; // penalty for mainland for navals
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -451,11 +451,11 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
for (const i of cells.i) {
|
||||
if (cells.h[i] < 20 || cells.burg[i]) continue; // do not overwrite burgs
|
||||
if (cells.c[i].some(c => burgs[cells.burg[c]].capital)) continue; // do not overwrite near capital
|
||||
const neibs = cells.c[i].filter(c => cells.h[c] >= 20);
|
||||
const adversaries = neibs.filter(c => cells.state[c] !== cells.state[i]);
|
||||
if (cells.c[i].some((c) => burgs[cells.burg[c]].capital)) continue; // do not overwrite near capital
|
||||
const neibs = cells.c[i].filter((c) => cells.h[c] >= 20);
|
||||
const adversaries = neibs.filter((c) => cells.state[c] !== cells.state[i]);
|
||||
if (adversaries.length < 2) continue;
|
||||
const buddies = neibs.filter(c => cells.state[c] === cells.state[i]);
|
||||
const buddies = neibs.filter((c) => cells.state[c] === cells.state[i]);
|
||||
if (buddies.length > 2) continue;
|
||||
if (adversaries.length <= buddies.length) continue;
|
||||
cells.state[i] = cells.state[adversaries[0]];
|
||||
|
|
@ -503,7 +503,7 @@ window.BurgsAndStates = (function () {
|
|||
const visualCenter = findCell(s.pole[0], s.pole[1]);
|
||||
const start = cells.state[visualCenter] === s.i ? visualCenter : s.center;
|
||||
const hull = getHull(start, s.i, s.cells / 10);
|
||||
const points = [...hull].map(v => pack.vertices.p[v]);
|
||||
const points = [...hull].map((v) => pack.vertices.p[v]);
|
||||
const delaunay = Delaunator.from(points);
|
||||
const voronoi = new Voronoi(delaunay, points, points.length);
|
||||
const chain = connectCenters(voronoi.vertices, s.pole[1]);
|
||||
|
|
@ -541,7 +541,7 @@ window.BurgsAndStates = (function () {
|
|||
return used[findCell(p[0], p[1])];
|
||||
});
|
||||
|
||||
const pointsInside = d3.range(c.p.length).filter(i => inside[i]);
|
||||
const pointsInside = d3.range(c.p.length).filter((i) => inside[i]);
|
||||
if (!pointsInside.length) return [0];
|
||||
const h = c.p.length < 200 ? 0 : c.p.length < 600 ? 0.5 : 1; // power of horyzontality shift
|
||||
const end =
|
||||
|
|
@ -600,14 +600,14 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
if (!list) {
|
||||
// remove all labels and textpaths
|
||||
g.selectAll("text").remove();
|
||||
g.selectAll('text').remove();
|
||||
t.selectAll("path[id*='stateLabel']").remove();
|
||||
}
|
||||
|
||||
const example = g.append("text").attr("x", 0).attr("x", 0).text("Average");
|
||||
const example = g.append('text').attr('x', 0).attr('x', 0).text('Average');
|
||||
const letterLength = example.node().getComputedTextLength() / 7; // average length of 1 letter
|
||||
|
||||
paths.forEach(p => {
|
||||
paths.forEach((p) => {
|
||||
const id = p[0];
|
||||
const state = states[p[0]];
|
||||
const {name, fullName} = state;
|
||||
|
|
@ -738,7 +738,7 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
|
||||
// convert neighbors Set object into array
|
||||
states.forEach(s => {
|
||||
states.forEach((s) => {
|
||||
if (!s.neighbors) return;
|
||||
s.neighbors = Array.from(s.neighbors);
|
||||
});
|
||||
|
|
@ -754,14 +754,14 @@ window.BurgsAndStates = (function () {
|
|||
pack.states.forEach(s => {
|
||||
if (!s.i || s.removed) return;
|
||||
const neibs = s.neighbors;
|
||||
s.color = colors.find(c => neibs.every(n => pack.states[n].color !== c));
|
||||
s.color = colors.find((c) => neibs.every((n) => pack.states[n].color !== c));
|
||||
if (!s.color) s.color = getRandomColor();
|
||||
colors.push(colors.shift());
|
||||
});
|
||||
|
||||
// randomize each already used color a bit
|
||||
colors.forEach(c => {
|
||||
const sameColored = pack.states.filter(s => s.color === c);
|
||||
colors.forEach((c) => {
|
||||
const sameColored = pack.states.filter((s) => s.color === c);
|
||||
sameColored.forEach((s, d) => {
|
||||
if (!d) return;
|
||||
s.color = getMixedColor(s.color);
|
||||
|
|
@ -823,9 +823,9 @@ window.BurgsAndStates = (function () {
|
|||
for (let f = 1; f < states.length; f++) {
|
||||
if (states[f].removed) continue;
|
||||
|
||||
if (states[f].diplomacy.includes("Vassal")) {
|
||||
if (states[f].diplomacy.includes('Vassal')) {
|
||||
// Vassals copy relations from their Suzerains
|
||||
const suzerain = states[f].diplomacy.indexOf("Vassal");
|
||||
const suzerain = states[f].diplomacy.indexOf('Vassal');
|
||||
|
||||
for (let i = 1; i < states.length; i++) {
|
||||
if (i === f || i === suzerain) continue;
|
||||
|
|
@ -833,7 +833,7 @@ window.BurgsAndStates = (function () {
|
|||
if (states[suzerain].diplomacy[i] === "Suzerain") states[f].diplomacy[i] = "Ally";
|
||||
for (let e = 1; e < states.length; e++) {
|
||||
if (e === f || e === suzerain) continue;
|
||||
if (states[e].diplomacy[suzerain] === "Suzerain" || states[e].diplomacy[suzerain] === "Vassal") continue;
|
||||
if (states[e].diplomacy[suzerain] === 'Suzerain' || states[e].diplomacy[suzerain] === 'Vassal') continue;
|
||||
states[e].diplomacy[f] = states[e].diplomacy[suzerain];
|
||||
}
|
||||
}
|
||||
|
|
@ -843,8 +843,8 @@ window.BurgsAndStates = (function () {
|
|||
for (let t = f + 1; t < states.length; t++) {
|
||||
if (states[t].removed) continue;
|
||||
|
||||
if (states[t].diplomacy.includes("Vassal")) {
|
||||
const suzerain = states[t].diplomacy.indexOf("Vassal");
|
||||
if (states[t].diplomacy.includes('Vassal')) {
|
||||
const suzerain = states[t].diplomacy.indexOf('Vassal');
|
||||
states[f].diplomacy[t] = states[f].diplomacy[suzerain];
|
||||
continue;
|
||||
}
|
||||
|
|
@ -882,9 +882,9 @@ window.BurgsAndStates = (function () {
|
|||
for (let attacker = 1; attacker < states.length; attacker++) {
|
||||
const ad = states[attacker].diplomacy; // attacker relations;
|
||||
if (states[attacker].removed) continue;
|
||||
if (!ad.includes("Rival")) continue; // no rivals to attack
|
||||
if (ad.includes("Vassal")) continue; // not independent
|
||||
if (ad.includes("Enemy")) continue; // already at war
|
||||
if (!ad.includes('Rival')) continue; // no rivals to attack
|
||||
if (ad.includes('Vassal')) continue; // not independent
|
||||
if (ad.includes('Enemy')) continue; // already at war
|
||||
|
||||
// random independent rival
|
||||
const defender = ra(
|
||||
|
|
@ -922,8 +922,8 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
});
|
||||
|
||||
ap = d3.sum(attackers.map(a => states[a].area * states[a].expansionism)); // attackers joined power
|
||||
dp = d3.sum(defenders.map(d => states[d].area * states[d].expansionism)); // defender joined power
|
||||
ap = d3.sum(attackers.map((a) => states[a].area * states[a].expansionism)); // attackers joined power
|
||||
dp = d3.sum(defenders.map((d) => states[d].area * states[d].expansionism)); // defender joined power
|
||||
|
||||
// defender allies join
|
||||
dd.forEach((r, d) => {
|
||||
|
|
@ -931,7 +931,7 @@ window.BurgsAndStates = (function () {
|
|||
if (states[d].diplomacy[attacker] !== "Rival" && ap / dp > 2 * gauss(1.6, 0.8, 0, 10, 2)) {
|
||||
const reason = states[d].diplomacy.includes("Enemy") ? "Being already at war," : `Frightened by ${an},`;
|
||||
war.push(`${reason} ${states[d].name} severed the defense pact with ${dn}`);
|
||||
dd[d] = states[d].diplomacy[defender] = "Suspicion";
|
||||
dd[d] = states[d].diplomacy[defender] = 'Suspicion';
|
||||
return;
|
||||
}
|
||||
defenders.push(d);
|
||||
|
|
@ -951,7 +951,7 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
// attacker allies join if the defender is their rival or joined power > defenders power and defender is not an ally
|
||||
ad.forEach((r, d) => {
|
||||
if (r !== "Ally" || states[d].diplomacy.includes("Vassal") || defenders.includes(d)) return;
|
||||
if (r !== 'Ally' || states[d].diplomacy.includes('Vassal') || defenders.includes(d)) return;
|
||||
const name = states[d].name;
|
||||
if (states[d].diplomacy[defender] !== "Rival" && (P(0.2) || ap <= dp * 1.2)) {
|
||||
war.push(`${an}'s ally ${name} avoided entering the war`);
|
||||
|
|
@ -983,7 +983,7 @@ window.BurgsAndStates = (function () {
|
|||
chronicle.push(war); // add a record to diplomatical history
|
||||
}
|
||||
|
||||
TIME && console.timeEnd("generateDiplomacy");
|
||||
TIME && console.timeEnd('generateDiplomacy');
|
||||
//console.table(states.map(s => s.diplomacy));
|
||||
};
|
||||
|
||||
|
|
@ -1064,33 +1064,33 @@ window.BurgsAndStates = (function () {
|
|||
if (P(0.3) && s.diplomacy.includes("Vassal")) return "Protectorate"; // some vassals
|
||||
}
|
||||
|
||||
if (base === 16 && (form === "Empire" || form === "Kingdom")) return "Sultanate"; // Turkic
|
||||
if (base === 5 && (form === "Empire" || form === "Kingdom")) return "Tsardom"; // Ruthenian
|
||||
if ([16, 31].includes(base) && (form === "Empire" || form === "Kingdom")) return "Khaganate"; // Turkic, Mongolian
|
||||
if (base === 12 && (form === "Kingdom" || form === "Grand Duchy")) return "Shogunate"; // Japanese
|
||||
if ([18, 17].includes(base) && form === "Empire") return "Caliphate"; // Arabic, Berber
|
||||
if (base === 18 && (form === "Grand Duchy" || form === "Duchy")) return "Emirate"; // Arabic
|
||||
if (base === 7 && (form === "Grand Duchy" || form === "Duchy")) return "Despotate"; // Greek
|
||||
if (base === 31 && (form === "Grand Duchy" || form === "Duchy")) return "Ulus"; // Mongolian
|
||||
if (base === 16 && (form === "Grand Duchy" || form === "Duchy")) return "Horde"; // Turkic
|
||||
if (base === 24 && (form === "Grand Duchy" || form === "Duchy")) return "Satrapy"; // Iranian
|
||||
if (base === 16 && (form === 'Empire' || form === 'Kingdom')) return 'Sultanate'; // Turkic
|
||||
if (base === 5 && (form === 'Empire' || form === 'Kingdom')) return 'Tsardom'; // Ruthenian
|
||||
if ([16, 31].includes(base) && (form === 'Empire' || form === 'Kingdom')) return 'Khaganate'; // Turkic, Mongolian
|
||||
if (base === 12 && (form === 'Kingdom' || form === 'Grand Duchy')) return 'Shogunate'; // Japanese
|
||||
if ([18, 17].includes(base) && form === 'Empire') return 'Caliphate'; // Arabic, Berber
|
||||
if (base === 18 && (form === 'Grand Duchy' || form === 'Duchy')) return 'Emirate'; // Arabic
|
||||
if (base === 7 && (form === 'Grand Duchy' || form === 'Duchy')) return 'Despotate'; // Greek
|
||||
if (base === 31 && (form === 'Grand Duchy' || form === 'Duchy')) return 'Ulus'; // Mongolian
|
||||
if (base === 16 && (form === 'Grand Duchy' || form === 'Duchy')) return 'Horde'; // Turkic
|
||||
if (base === 24 && (form === 'Grand Duchy' || form === 'Duchy')) return 'Satrapy'; // Iranian
|
||||
return form;
|
||||
}
|
||||
|
||||
if (s.form === "Republic") {
|
||||
if (s.form === 'Republic') {
|
||||
// Default name is from weighted array, special case for small states with only 1 burg
|
||||
if (tier < 2 && s.burgs === 1) {
|
||||
if (trimVowels(s.name) === trimVowels(pack.burgs[s.capital].name)) {
|
||||
s.name = pack.burgs[s.capital].name;
|
||||
return "Free City";
|
||||
return 'Free City';
|
||||
}
|
||||
if (P(0.3)) return "City-state";
|
||||
}
|
||||
return rw(republic);
|
||||
}
|
||||
|
||||
if (s.form === "Union") return rw(union);
|
||||
if (s.form === "Anarchy") return rw(anarchy);
|
||||
if (s.form === 'Union') return rw(union);
|
||||
if (s.form === 'Anarchy') return rw(anarchy);
|
||||
|
||||
if (s.form === "Theocracy") {
|
||||
// European
|
||||
|
|
@ -1213,7 +1213,7 @@ window.BurgsAndStates = (function () {
|
|||
const name = nameByBurg ? stateBurgs[i].name : Names.getState(Names.getCultureShort(c), c);
|
||||
const formName = rw(form);
|
||||
form[formName] += 10;
|
||||
const fullName = name + " " + formName;
|
||||
const fullName = name + ' ' + formName;
|
||||
const color = getMixedColor(s.color);
|
||||
const kinship = nameByBurg ? 0.8 : 0.4;
|
||||
const type = getType(center, burg.port);
|
||||
|
|
@ -1258,10 +1258,10 @@ window.BurgsAndStates = (function () {
|
|||
// justify provinces shapes a bit
|
||||
for (const i of cells.i) {
|
||||
if (cells.burg[i]) continue; // do not overwrite burgs
|
||||
const neibs = cells.c[i].filter(c => cells.state[c] === cells.state[i]).map(c => cells.province[c]);
|
||||
const adversaries = neibs.filter(c => c !== cells.province[i]);
|
||||
const neibs = cells.c[i].filter((c) => cells.state[c] === cells.state[i]).map((c) => cells.province[c]);
|
||||
const adversaries = neibs.filter((c) => c !== cells.province[i]);
|
||||
if (adversaries.length < 2) continue;
|
||||
const buddies = neibs.filter(c => c === cells.province[i]).length;
|
||||
const buddies = neibs.filter((c) => c === cells.province[i]).length;
|
||||
if (buddies.length > 2) continue;
|
||||
const competitors = adversaries.map(p => adversaries.reduce((s, v) => (v === p ? s + 1 : s), 0));
|
||||
const max = d3.max(competitors);
|
||||
|
|
@ -1270,8 +1270,8 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
|
||||
// add "wild" provinces if some cells don't have a province assigned
|
||||
const noProvince = Array.from(cells.i).filter(i => cells.state[i] && !cells.province[i]); // cells without province assigned
|
||||
states.forEach(s => {
|
||||
const noProvince = Array.from(cells.i).filter((i) => cells.state[i] && !cells.province[i]); // cells without province assigned
|
||||
states.forEach((s) => {
|
||||
if (!s.provinces.length) return;
|
||||
|
||||
const coreProvinceNames = s.provinces.map(p => provinces[p]?.name);
|
||||
|
|
@ -1288,7 +1288,7 @@ window.BurgsAndStates = (function () {
|
|||
while (stateNoProvince.length) {
|
||||
// add new province
|
||||
const province = provinces.length;
|
||||
const burgCell = stateNoProvince.find(i => cells.burg[i]);
|
||||
const burgCell = stateNoProvince.find((i) => cells.burg[i]);
|
||||
const center = burgCell ? burgCell : stateNoProvince[0];
|
||||
const burg = burgCell ? cells.burg[burgCell] : 0;
|
||||
cells.province[center] = province;
|
||||
|
|
@ -1349,7 +1349,6 @@ window.BurgsAndStates = (function () {
|
|||
const type = getType(center, burgs[burg]?.port);
|
||||
const coa = COA.generate(s.coa, kinship, dominion, type);
|
||||
coa.shield = COA.getShield(c, s.i);
|
||||
|
||||
provinces.push({i: province, state: s.i, center, burg, name, formName, fullName, color, coa});
|
||||
s.provinces.push(province);
|
||||
|
||||
|
|
@ -1362,7 +1361,7 @@ window.BurgsAndStates = (function () {
|
|||
while (queue.length) {
|
||||
const current = queue.pop();
|
||||
if (current === to) return true; // way is found
|
||||
cells.c[current].forEach(c => {
|
||||
cells.c[current].forEach((c) => {
|
||||
if (used[c] || cells.h[c] < 20 || cells.state[c] !== state) return;
|
||||
queue.push(c);
|
||||
used[c] = 1;
|
||||
|
|
@ -1372,7 +1371,7 @@ window.BurgsAndStates = (function () {
|
|||
}
|
||||
|
||||
// re-check
|
||||
stateNoProvince = noProvince.filter(i => cells.state[i] === s.i && !cells.province[i]);
|
||||
stateNoProvince = noProvince.filter((i) => cells.state[i] === s.i && !cells.province[i]);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1942,6 +1942,7 @@ function toggleResources(event) {
|
|||
function drawResources() {
|
||||
console.time('drawResources');
|
||||
const someArePinned = pack.resources.some((resource) => resource.pinned);
|
||||
const drawCircle = +goods.attr('data-circle');
|
||||
|
||||
let resourcesHTML = '';
|
||||
for (const i of pack.cells.i) {
|
||||
|
|
@ -1951,11 +1952,17 @@ function drawResources() {
|
|||
const [x, y] = pack.cells.p[i];
|
||||
const stroke = Resources.getStroke(resource.color);
|
||||
|
||||
if (!drawCircle) {
|
||||
resourcesHTML += `<use href="#${resource.icon}" x="${x - 3}" y="${y - 3}" width="6" height="6"/>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
resourcesHTML += `<g>
|
||||
<circle data-i="${resource.i}" cx=${x} cy=${y} r="3" fill="${resource.color}" stroke="${stroke}" />
|
||||
<use href="#${resource.icon}" x="${x - 3}" y="${y - 3}" width="6" height="6"/>
|
||||
</g>`;
|
||||
}
|
||||
|
||||
goods.html(resourcesHTML);
|
||||
console.timeEnd('drawResources');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -727,6 +727,12 @@ styleResourcesCircle.addEventListener('change', function () {
|
|||
drawResources();
|
||||
});
|
||||
|
||||
styleResourcesCircle.addEventListener('change', function () {
|
||||
goods.attr('data-circle', +this.checked);
|
||||
goods.selectAll('*').remove();
|
||||
drawResources();
|
||||
});
|
||||
|
||||
// request a URL to image to be used as a texture
|
||||
function textureProvideURL() {
|
||||
alertMessage.innerHTML = /* html */ `Provide an image URL to be used as a texture:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue