Merge branch 'master' of https://github.com/Azgaar/Fantasy-Map-Generator into dev-economics

This commit is contained in:
Azgaar 2021-08-05 00:09:16 +03:00
commit 1180a3c67b
41 changed files with 5185 additions and 3469 deletions

View file

@ -1,12 +1,9 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? (module.exports = factory()) : typeof define === 'function' && define.amd ? define(factory) : (global.BurgsAndStates = factory());
})(this, function () {
'use strict';
'use strict';
window.BurgsAndStates = (function () {
const generate = function () {
const cells = pack.cells,
cultures = pack.cultures,
n = cells.i.length;
const {cells, cultures} = pack;
const n = cells.i.length;
cells.burg = new Uint16Array(n); // cell burg
cells.road = new Uint16Array(n); // cell road power
@ -80,6 +77,7 @@
TIME && console.time('createStates');
const states = [{i: 0, name: 'Neutrals'}];
const colors = getColors(burgs.length - 1);
const each5th = each(5);
burgs.forEach(function (b, i) {
if (!i) return; // skip first element
@ -93,7 +91,7 @@
// states data
const expansionism = rn(Math.random() * powerInput.value + 1, 1);
const basename = b.name.length < 9 && b.cell % 5 === 0 ? b.name : Names.getCultureShort(b.culture);
const basename = b.name.length < 9 && each5th(b.cell) ? b.name : Names.getCultureShort(b.culture);
const name = Names.getState(basename, b.culture);
const type = cultures[b.culture].type;
@ -110,10 +108,10 @@
// place secondary settlements based on geo and economical evaluation
function placeTowns() {
TIME && console.time('placeTowns');
const score = new Int16Array(cells.s.map((s) => s * Math.random())); // a bit randomized cell score for towns placement
const sorted = cells.i.filter((i) => score[i] > 0 && cells.culture[i] && !cells.burg[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes
const score = new Int16Array(cells.s.map((s) => s * gauss(1, 3, 0, 20, 3))); // a bit randomized cell score for towns placement
const sorted = cells.i.filter((i) => !cells.burg[i] && score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes
const desiredNumber = manorsInput.value == 1000 ? rn(sorted.length / 6 / (grid.points.length / 10000) ** 0.8) : +manorsInput.value;
const desiredNumber = manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) : manorsInput.valueAsNumber;
const burgsNumber = Math.min(desiredNumber, sorted.length); // towns to generate
let burgsAdded = 0;
@ -175,9 +173,9 @@
if (b.port) {
b.population = b.population * 1.3; // increase port population
const e = cells.v[i].filter((v) => vertices.c[v].some((c) => c === cells.haven[i])); // vertices of common edge
b.x = rn((vertices.p[e[0]][0] + vertices.p[e[1]][0]) / 2, 2);
b.y = rn((vertices.p[e[0]][1] + vertices.p[e[1]][1]) / 2, 2);
const [x, y] = getMiddlePoint(i, haven);
b.x = x;
b.y = y;
}
// add random factor
@ -477,9 +475,7 @@
// calculate and draw curved state labels for a list of states
const drawStateLabels = function (list) {
TIME && console.time('drawStateLabels');
const cells = pack.cells,
features = pack.features,
states = pack.states;
const {cells, features, states} = pack;
const paths = []; // text paths
lineGen.curve(d3.curveBundle.beta(1));
@ -572,8 +568,8 @@
}
void (function drawLabels() {
const g = labels.select('#states'),
t = defs.select('#textPaths');
const g = labels.select('#states');
const t = defs.select('#textPaths');
const displayed = layerIsOn('toggleLabels');
if (!displayed) toggleLabels();
@ -602,8 +598,8 @@
.attr('id', 'textPath_stateLabel' + id);
const pathLength = p[1].length > 1 ? textPath.node().getTotalLength() / letterLength : 0; // path length in letters
let lines = [],
ratio = 100;
let lines = [];
let ratio = 100;
if (pathLength < s.name.length) {
// only short name will fit
@ -622,10 +618,9 @@
// prolongate path if it's too short
if (pathLength && pathLength < lines[0].length) {
const points = p[1];
const f = points[0],
l = points[points.length - 1];
const dx = l[0] - f[0],
dy = l[1] - f[1];
const f = points[0];
const l = points[points.length - 1];
const [dx, dy] = [l[0] - f[0], l[1] - f[1]];
const mod = Math.abs((letterLength * lines[0].length) / dx) / 2;
points[0] = [rn(f[0] - dx * mod), rn(f[1] - dy * mod)];
points[points.length - 1] = [rn(l[0] + dx * mod), rn(l[1] + dy * mod)];
@ -653,8 +648,8 @@
if (lines.length < 2) return;
// check whether multilined label is generally inside the state. If no, replace with short name label
const cs = pack.cells.state,
b = el.parentNode.getBBox();
const cs = pack.cells.state;
const b = el.parentNode.getBBox();
const c1 = () => +cs[findCell(b.x, b.y)] === id;
const c2 = () => +cs[findCell(b.x + b.width / 2, b.y)] === id;
const c3 = () => +cs[findCell(b.x + b.width, b.y)] === id;
@ -950,30 +945,31 @@
});
const monarchy = ['Duchy', 'Grand Duchy', 'Principality', 'Kingdom', 'Empire']; // per expansionism tier
const republic = {Republic: 75, Federation: 4, Oligarchy: 2, Tetrarchy: 1, Triumvirate: 1, Diarchy: 1, 'Trade Company': 4, Junta: 1}; // weighted random
const republic = {Republic: 75, Federation: 4, Oligarchy: 2, 'Most Serene Republic': 2, Tetrarchy: 1, Triumvirate: 1, Diarchy: 1, 'Trade Company': 4, Junta: 1}; // weighted random
const union = {Union: 3, League: 4, Confederation: 1, 'United Kingdom': 1, 'United Republic': 1, 'United Provinces': 2, Commonwealth: 1, Heptarchy: 1}; // weighted random
const theocracy = {Theocracy: 20, Brotherhood: 1, Thearchy: 2, See: 1};
const theocracy = {Theocracy: 20, Brotherhood: 1, Thearchy: 2, See: 1, 'Holy State': 1};
const anarchy = {'Free Territory': 2, Council: 3, Commune: 1, Community: 1};
for (const s of states) {
if (list && !list.includes(s.i)) continue;
const tier = expTiers[s.i];
const religion = pack.cells.religion[s.center];
const isTheocracy = (religion && pack.religions[religion].expansion === 'state') || (P(0.1) && ['Organized', 'Cult'].includes(pack.religions[religion].type));
const isAnarchy = P(0.01 - expTiers[s.i] / 500);
const isAnarchy = P(0.01 - tier / 500);
if (isTheocracy) s.form = 'Theocracy';
else if (isAnarchy) s.form = 'Anarchy';
else s.form = s.type === 'Naval' ? rw(naval) : rw(generic);
s.formName = selectForm(s);
s.formName = selectForm(s, tier);
s.fullName = getFullName(s);
}
function selectForm(s) {
function selectForm(s, tier) {
const base = pack.cultures[s.culture].base;
if (s.form === 'Monarchy') {
const form = monarchy[expTiers[s.i]];
const form = monarchy[tier];
// Default name depends on exponent tier, some culture bases have special names for tiers
if (s.diplomacy) {
if (form === 'Duchy' && s.neighbors.length > 1 && rand(6) < s.neighbors.length && s.diplomacy.includes('Vassal')) return 'Marches'; // some vassal dutchies on borderland
@ -995,7 +991,7 @@
if (s.form === 'Republic') {
// Default name is from weighted array, special case for small states with only 1 burg
if (expTiers[s.i] < 2 && s.burgs === 1) {
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';
@ -1009,10 +1005,15 @@
if (s.form === 'Anarchy') return rw(anarchy);
if (s.form === 'Theocracy') {
if (P(0.5) && [0, 1, 2, 3, 4, 6, 8, 9, 13, 15, 20].includes(base)) return 'Diocese'; // Euporean
if (P(0.9) && [7, 5].includes(base)) return 'Eparchy'; // Greek, Ruthenian
// European
if ([0, 1, 2, 3, 4, 6, 8, 9, 13, 15, 20].includes(base)) {
if (P(0.1)) return 'Divine ' + monarchy[tier];
if (tier < 2 && P(0.5)) return 'Diocese';
if (tier < 2 && P(0.5)) return 'Bishopric';
}
if (tier < 2 && P(0.9) && [7, 5].includes(base)) return 'Eparchy'; // Greek, Ruthenian
if (P(0.9) && [21, 16].includes(base)) return 'Imamah'; // Nigerian, Turkish
if (P(0.8) && [18, 17, 28].includes(base)) return 'Caliphate'; // Arabic, Berber, Swahili
if (tier > 2 && P(0.8) && [18, 17, 28].includes(base)) return 'Caliphate'; // Arabic, Berber, Swahili
return rw(theocracy);
}
}
@ -1255,4 +1256,4 @@
generateProvinces,
updateCultures
};
});
})();