mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-19 18:41:23 +01:00
feat: zones - generation fixes
This commit is contained in:
parent
fdf0d163a8
commit
c17be58efe
4 changed files with 116 additions and 105 deletions
|
|
@ -611,8 +611,7 @@ window.BurgsAndStates = (() => {
|
|||
// generate Diplomatic Relationships
|
||||
const generateDiplomacy = () => {
|
||||
TIME && console.time("generateDiplomacy");
|
||||
const cells = pack.cells,
|
||||
states = pack.states;
|
||||
const {cells, states} = pack;
|
||||
const chronicle = (states[0].diplomacy = []);
|
||||
const valid = states.filter(s => s.i && !states.removed);
|
||||
|
||||
|
|
@ -696,21 +695,23 @@ window.BurgsAndStates = (() => {
|
|||
const defender = ra(
|
||||
ad.map((r, d) => (r === "Rival" && !states[d].diplomacy.includes("Vassal") ? d : 0)).filter(d => d)
|
||||
);
|
||||
let ap = states[attacker].area * states[attacker].expansionism,
|
||||
dp = states[defender].area * states[defender].expansionism;
|
||||
let ap = states[attacker].area * states[attacker].expansionism;
|
||||
let dp = states[defender].area * states[defender].expansionism;
|
||||
if (ap < dp * gauss(1.6, 0.8, 0, 10, 2)) continue; // defender is too strong
|
||||
const an = states[attacker].name,
|
||||
dn = states[defender].name; // names
|
||||
const attackers = [attacker],
|
||||
defenders = [defender]; // attackers and defenders array
|
||||
|
||||
const an = states[attacker].name;
|
||||
const dn = states[defender].name; // names
|
||||
const attackers = [attacker];
|
||||
const defenders = [defender]; // attackers and defenders array
|
||||
const dd = states[defender].diplomacy; // defender relations;
|
||||
|
||||
// start a war
|
||||
const war = [`${an}-${trimVowels(dn)}ian War`, `${an} declared a war on its rival ${dn}`];
|
||||
const end = options.year;
|
||||
const start = end - gauss(2, 2, 0, 5);
|
||||
states[attacker].campaigns.push({name: `${trimVowels(dn)}ian War`, start, end});
|
||||
states[defender].campaigns.push({name: `${trimVowels(an)}ian War`, start, end});
|
||||
// start an ongoing war
|
||||
const name = `${an}-${trimVowels(dn)}ian War`;
|
||||
const start = options.year - gauss(2, 3, 0, 10);
|
||||
const war = [name, `${an} declared a war on its rival ${dn}`];
|
||||
const campaign = {name, start, attacker, defender};
|
||||
states[attacker].campaigns.push(campaign);
|
||||
states[defender].campaigns.push(campaign);
|
||||
|
||||
// attacker vassals join the war
|
||||
ad.forEach((r, d) => {
|
||||
|
|
@ -790,7 +791,6 @@ window.BurgsAndStates = (() => {
|
|||
}
|
||||
|
||||
TIME && console.timeEnd("generateDiplomacy");
|
||||
//console.table(states.map(s => s.diplomacy));
|
||||
};
|
||||
|
||||
// select a forms for listed or all valid states
|
||||
|
|
|
|||
|
|
@ -503,7 +503,9 @@ window.Military = (function () {
|
|||
: "";
|
||||
|
||||
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 year = campaign
|
||||
? rand(campaign.start, campaign.end || options.year)
|
||||
: gauss(options.year - 100, 150, 1, options.year - 6);
|
||||
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});
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ function editZones() {
|
|||
|
||||
const zoneId = +body.querySelector("div.selected")?.dataset.id;
|
||||
const zone = pack.zones.find(z => z.i === zoneId);
|
||||
if (!zone) return;
|
||||
|
||||
if (eraseMode) {
|
||||
const data = zones
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
window.Zones = (function () {
|
||||
const config = {
|
||||
invasion: {quantity: 1.8, generate: addInvasion}, // invasion of enemy lands
|
||||
rebels: {quantity: 1.6, generate: addRebels}, // rebels along a state border
|
||||
invasion: {quantity: 2, generate: addInvasion}, // invasion of enemy lands
|
||||
rebels: {quantity: 1.5, generate: addRebels}, // rebels along a state border
|
||||
proselytism: {quantity: 1.6, generate: addProselytism}, // proselitism of organized religion
|
||||
crusade: {quantity: 1.6, generate: addCrusade}, // crusade on heresy lands
|
||||
disease: {quantity: 1.8, generate: addDisease}, // disease starting in a random city
|
||||
disaster: {quantity: 1.2, generate: addDisaster}, // disaster starting in a random city
|
||||
eruption: {quantity: 1.4, generate: addEruption}, // volcanic eruption aroung volcano
|
||||
avalanche: {quantity: 1.0, generate: addAvalanche}, // avalanche impacting highland road
|
||||
eruption: {quantity: 1.2, generate: addEruption}, // volcanic eruption aroung volcano
|
||||
avalanche: {quantity: 0.8, generate: addAvalanche}, // avalanche impacting highland road
|
||||
fault: {quantity: 1.4, generate: addFault}, // fault line in elevated areas
|
||||
flood: {quantity: 1.4, generate: addFlood}, // flood on river banks
|
||||
tsunami: {quantity: 1.2, generate: addTsunami} // tsunami starting near coast
|
||||
|
|
@ -21,152 +21,160 @@ window.Zones = (function () {
|
|||
const usedCells = new Uint8Array(pack.cells.i.length);
|
||||
pack.zones = [];
|
||||
|
||||
Object.values(config).forEach(type => {
|
||||
const count = rn(Math.random() * type.quantity * globalModifier);
|
||||
for (let i = 0; i < count; i++) {
|
||||
type.generate(usedCells);
|
||||
}
|
||||
Object.entries(config).forEach(([name, type]) => {
|
||||
const expectedNumber = type.quantity * globalModifier;
|
||||
let number = gauss(expectedNumber, expectedNumber / 2, 0, 100);
|
||||
console.log(name, number);
|
||||
while (number--) type.generate(usedCells);
|
||||
});
|
||||
|
||||
TIME && console.timeEnd("generateZones");
|
||||
};
|
||||
|
||||
function addInvasion(usedCells) {
|
||||
const atWar = pack.states.filter(s => s.diplomacy && s.diplomacy.some(d => d === "Enemy"));
|
||||
if (!atWar.length) return;
|
||||
const {cells, states} = pack;
|
||||
|
||||
const invader = ra(atWar);
|
||||
const target = invader.diplomacy.find(d => d === "Enemy");
|
||||
const ongoingConflicts = states
|
||||
.filter(s => s.i && !s.removed && s.campaigns)
|
||||
.map(s => s.campaigns)
|
||||
.flat()
|
||||
.filter(c => !c.end);
|
||||
if (!ongoingConflicts.length) return;
|
||||
const {defender, attacker} = ra(ongoingConflicts);
|
||||
|
||||
const cells = pack.cells;
|
||||
const cell = ra(
|
||||
cells.i.filter(i => cells.state[i] === target.i && cells.c[i].some(c => cells.state[c] === invader.i))
|
||||
);
|
||||
if (!cell) return;
|
||||
const borderCells = cells.i.filter(cellId => {
|
||||
if (usedCells[cellId]) return false;
|
||||
if (cells.state[cellId] !== defender) return false;
|
||||
return cells.c[cellId].some(c => cells.state[c] === attacker);
|
||||
});
|
||||
|
||||
const cellsArray = [],
|
||||
queue = [cell],
|
||||
power = rand(5, 30);
|
||||
const startCell = ra(borderCells);
|
||||
if (startCell === undefined) return;
|
||||
|
||||
const invationCells = [];
|
||||
const queue = [startCell];
|
||||
const maxCells = rand(5, 30);
|
||||
|
||||
while (queue.length) {
|
||||
const q = P(0.4) ? queue.shift() : queue.pop();
|
||||
cellsArray.push(q);
|
||||
if (cellsArray.length > power) break;
|
||||
const cellId = P(0.4) ? queue.shift() : queue.pop();
|
||||
invationCells.push(cellId);
|
||||
if (invationCells.length >= maxCells) break;
|
||||
|
||||
cells.c[q].forEach(e => {
|
||||
if (usedCells[e]) return;
|
||||
if (cells.state[e] !== target.i) return;
|
||||
usedCells[e] = 1;
|
||||
queue.push(e);
|
||||
cells.c[cellId].forEach(neibCellId => {
|
||||
if (usedCells[neibCellId]) return;
|
||||
if (cells.state[neibCellId] !== defender) return;
|
||||
usedCells[neibCellId] = 1;
|
||||
queue.push(neibCellId);
|
||||
});
|
||||
}
|
||||
|
||||
const invasion = rw({
|
||||
Invasion: 4,
|
||||
Occupation: 3,
|
||||
Raid: 2,
|
||||
Conquest: 2,
|
||||
const subtype = rw({
|
||||
Invasion: 5,
|
||||
Occupation: 4,
|
||||
Conquest: 3,
|
||||
Incursion: 2,
|
||||
Intervention: 2,
|
||||
Subjugation: 1,
|
||||
Foray: 1,
|
||||
Skirmishes: 1,
|
||||
Incursion: 2,
|
||||
Pillaging: 1,
|
||||
Intervention: 1
|
||||
Raid: 1
|
||||
});
|
||||
const name = getAdjective(invader.name) + " " + invasion;
|
||||
pack.zones.push({i: pack.zones.length, name, type: "Invasion", cells: cellsArray, color: "url(#hatch1)"});
|
||||
const name = getAdjective(states[attacker].name) + " " + subtype;
|
||||
|
||||
pack.zones.push({i: pack.zones.length, name, type: "Invasion", cells: invationCells, color: "url(#hatch1)"});
|
||||
}
|
||||
|
||||
function addRebels(usedCells) {
|
||||
const {cells, states} = pack;
|
||||
|
||||
const state = ra(states.filter(s => s.i && !s.removed && s.neighbors.some(Boolean)));
|
||||
if (!state) return;
|
||||
|
||||
const neib = ra(state.neighbors.filter(n => n && !states[n].removed));
|
||||
if (!neib) return;
|
||||
const neibStateId = ra(state.neighbors.filter(n => n && !states[n].removed));
|
||||
if (!neibStateId) return;
|
||||
|
||||
const cell = cells.i.find(
|
||||
i => cells.state[i] === state.i && !state.removed && cells.c[i].some(c => cells.state[c] === neib)
|
||||
);
|
||||
const cellsArray = [];
|
||||
const queue = [];
|
||||
if (cell) queue.push(cell);
|
||||
|
||||
const power = rand(10, 30);
|
||||
const borderCellId = cells.i.find(
|
||||
i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neibStateId)
|
||||
);
|
||||
if (borderCellId) queue.push(borderCellId);
|
||||
const maxCells = rand(10, 30);
|
||||
|
||||
while (queue.length) {
|
||||
const q = queue.shift();
|
||||
cellsArray.push(q);
|
||||
if (cellsArray.length > power) break;
|
||||
const cellId = queue.shift();
|
||||
cellsArray.push(cellId);
|
||||
if (cellsArray.length >= maxCells) break;
|
||||
|
||||
cells.c[q].forEach(e => {
|
||||
if (usedCells[e]) return;
|
||||
if (cells.state[e] !== state.i) return;
|
||||
usedCells[e] = 1;
|
||||
if (e % 4 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return;
|
||||
queue.push(e);
|
||||
cells.c[cellId].forEach(neibCellId => {
|
||||
if (usedCells[neibCellId]) return;
|
||||
if (cells.state[neibCellId] !== state.i) return;
|
||||
usedCells[neibCellId] = 1;
|
||||
if (neibCellId % 4 !== 0 && !cells.c[neibCellId].some(c => cells.state[c] === neibStateId)) return;
|
||||
queue.push(neibCellId);
|
||||
});
|
||||
}
|
||||
|
||||
const rebels = rw({
|
||||
Rebels: 5,
|
||||
Insurgents: 2,
|
||||
Insurrection: 2,
|
||||
Mutineers: 1,
|
||||
Insurgents: 1,
|
||||
Rioters: 1,
|
||||
Separatists: 1,
|
||||
Secessionists: 1,
|
||||
Insurrection: 2,
|
||||
Rebellion: 1,
|
||||
Conspiracy: 2
|
||||
Conspiracy: 1
|
||||
});
|
||||
|
||||
const name = getAdjective(states[neib].name) + " " + rebels;
|
||||
const name = getAdjective(states[neibStateId].name) + " " + rebels;
|
||||
pack.zones.push({i: pack.zones.length, name, type: "Rebels", cells: cellsArray, color: "url(#hatch3)"});
|
||||
}
|
||||
|
||||
function addProselytism(usedCells) {
|
||||
const organized = ra(pack.religions.filter(r => r.type === "Organized"));
|
||||
if (!organized) return;
|
||||
const {cells, religions} = pack;
|
||||
|
||||
const cells = pack.cells;
|
||||
const cell = ra(
|
||||
cells.i.filter(
|
||||
i =>
|
||||
cells.religion[i] &&
|
||||
cells.religion[i] !== organized.i &&
|
||||
cells.c[i].some(c => cells.religion[c] === organized.i)
|
||||
)
|
||||
const organizedReligions = religions.filter(r => r.i && !r.removed && r.type === "Organized");
|
||||
const religion = ra(organizedReligions);
|
||||
if (!religion) return;
|
||||
|
||||
const targetBorderCells = cells.i.filter(
|
||||
i => cells.religion[i] !== religion.i && cells.c[i].some(c => cells.religion[c] === religion.i)
|
||||
);
|
||||
if (!cell) return;
|
||||
const target = cells.religion[cell];
|
||||
const cellsArray = [],
|
||||
queue = [cell],
|
||||
power = rand(10, 30);
|
||||
const startCell = ra(targetBorderCells);
|
||||
if (!startCell) return;
|
||||
|
||||
const targetReligionId = cells.religion[startCell];
|
||||
const proselytismCells = [];
|
||||
const queue = [startCell];
|
||||
const maxCells = rand(10, 30);
|
||||
|
||||
while (queue.length) {
|
||||
const q = queue.shift();
|
||||
cellsArray.push(q);
|
||||
if (cellsArray.length > power) break;
|
||||
const cellId = queue.shift();
|
||||
proselytismCells.push(cellId);
|
||||
if (proselytismCells.length >= maxCells) break;
|
||||
|
||||
cells.c[q].forEach(e => {
|
||||
if (usedCells[e]) return;
|
||||
if (cells.religion[e] !== target) return;
|
||||
if (cells.h[e] < 20) return;
|
||||
usedCells[e] = 1;
|
||||
//if (e%2 !== 0 && !cells.c[e].some(c => cells.state[c] === neib)) return;
|
||||
queue.push(e);
|
||||
cells.c[cellId].forEach(neibCellId => {
|
||||
if (usedCells[neibCellId]) return;
|
||||
if (cells.religion[neibCellId] !== targetReligionId) return;
|
||||
if (cells.h[neibCellId] < 20) return;
|
||||
usedCells[neibCellId] = 1;
|
||||
queue.push(neibCellId);
|
||||
});
|
||||
}
|
||||
|
||||
const name = getAdjective(organized.name.split(" ")[0]) + " Proselytism";
|
||||
pack.zones.push({i: pack.zones.length, name, type: "Proselytism", cells: cellsArray, color: "url(#hatch6)"});
|
||||
const name = getAdjective(religion.name.split(" ")[0]) + " Proselytism";
|
||||
pack.zones.push({i: pack.zones.length, name, type: "Proselytism", cells: proselytismCells, color: "url(#hatch6)"});
|
||||
}
|
||||
|
||||
function addCrusade(usedCells) {
|
||||
const heresy = ra(pack.religions.filter(r => r.type === "Heresy"));
|
||||
if (!heresy) return;
|
||||
const {cells, religions} = pack;
|
||||
|
||||
const cells = pack.cells;
|
||||
const heresies = religions.filter(r => !r.removed && r.type === "Heresy");
|
||||
if (!heresies.length) return;
|
||||
|
||||
const heresy = ra(heresies);
|
||||
const crusadeCells = cells.i.filter(i => !usedCells[i] && cells.religion[i] === heresy.i);
|
||||
if (!crusadeCells.length) return;
|
||||
crusadeCells.forEach(i => (usedCells[i] = 1));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue