mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
refactor: generate historical conflicts
This commit is contained in:
parent
a2192fb984
commit
9b3a3f2e48
11 changed files with 81 additions and 28 deletions
|
|
@ -4,13 +4,15 @@
|
||||||
let grid = {}; // initial graph based on jittered square grid and data
|
let grid = {}; // initial graph based on jittered square grid and data
|
||||||
let pack = {}; // packed graph and data
|
let pack = {}; // packed graph and data
|
||||||
|
|
||||||
|
let notes = [];
|
||||||
|
let events = {};
|
||||||
|
|
||||||
let seed;
|
let seed;
|
||||||
let mapId;
|
let mapId;
|
||||||
let mapHistory = [];
|
let mapHistory = [];
|
||||||
|
|
||||||
let elSelected;
|
let elSelected;
|
||||||
|
|
||||||
let notes = [];
|
|
||||||
let customization = 0;
|
let customization = 0;
|
||||||
|
|
||||||
let rulers;
|
let rulers;
|
||||||
|
|
|
||||||
|
|
@ -559,6 +559,7 @@ window.Markers = (function () {
|
||||||
const {cells, states} = pack;
|
const {cells, states} = pack;
|
||||||
|
|
||||||
const state = states[cells.state[cell]];
|
const state = states[cells.state[cell]];
|
||||||
|
// TODO: use events
|
||||||
if (!state.campaigns) state.campaigns = BurgsAndStates.generateCampaign(state);
|
if (!state.campaigns) state.campaigns = BurgsAndStates.generateCampaign(state);
|
||||||
const campaign = ra(state.campaigns);
|
const campaign = ra(state.campaigns);
|
||||||
const date = generateDate(campaign.start, campaign.end);
|
const date = generateDate(campaign.start, campaign.end);
|
||||||
|
|
|
||||||
|
|
@ -149,11 +149,8 @@ window.Names = (function () {
|
||||||
// generate short name for base
|
// generate short name for base
|
||||||
const getBaseShort = function (base) {
|
const getBaseShort = function (base) {
|
||||||
if (nameBases[base] === undefined) {
|
if (nameBases[base] === undefined) {
|
||||||
tip(
|
const message = `Namebase ${base} does not exist. Please upload custom namebases of change the base in Cultures Editor`;
|
||||||
`Namebase ${base} does not exist. Please upload custom namebases of change the base in Cultures Editor`,
|
tip(message, false, "error");
|
||||||
false,
|
|
||||||
"error"
|
|
||||||
);
|
|
||||||
base = 1;
|
base = 1;
|
||||||
}
|
}
|
||||||
const min = nameBases[base].min - 1;
|
const min = nameBases[base].min - 1;
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,14 @@ async function generate(options?: IGenerationOptions) {
|
||||||
window.mapCoordinates = calculateMapCoordinates();
|
window.mapCoordinates = calculateMapCoordinates();
|
||||||
|
|
||||||
const newGrid = await createGrid(grid, precreatedGraph);
|
const newGrid = await createGrid(grid, precreatedGraph);
|
||||||
const newPack = createPack(newGrid);
|
const {pack: newPack, conflicts} = createPack(newGrid);
|
||||||
|
|
||||||
// TODO: draw default ruler
|
// TODO: draw default ruler
|
||||||
|
|
||||||
// redefine global grid and pack
|
// redefine global grid and pack
|
||||||
grid = newGrid;
|
grid = newGrid;
|
||||||
pack = newPack;
|
pack = newPack;
|
||||||
|
events = {conflicts};
|
||||||
|
|
||||||
// temp rendering for debug
|
// temp rendering for debug
|
||||||
// renderLayer("cells");
|
// renderLayer("cells");
|
||||||
|
|
|
||||||
|
|
@ -113,3 +113,15 @@ export const relations = {
|
||||||
farStates: {Friendly: 1, Neutral: 12, Suspicion: 2},
|
farStates: {Friendly: 1, Neutral: 12, Suspicion: 2},
|
||||||
navalToNaval: {Neutral: 2, Suspicion: 2, Rival: 1}
|
navalToNaval: {Neutral: 2, Suspicion: 2, Rival: 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const conflictTypes = {
|
||||||
|
War: 6,
|
||||||
|
Conflict: 2,
|
||||||
|
Campaign: 4,
|
||||||
|
Invasion: 2,
|
||||||
|
Rebellion: 2,
|
||||||
|
Conquest: 2,
|
||||||
|
Intervention: 1,
|
||||||
|
Expedition: 1,
|
||||||
|
Crusade: 1
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export function generateBurgsAndStates(
|
||||||
rivers: Omit<IRiver, "name" | "basin" | "type">[],
|
rivers: Omit<IRiver, "name" | "basin" | "type">[],
|
||||||
vertices: IGraphVertices,
|
vertices: IGraphVertices,
|
||||||
cells: TCellsData
|
cells: TCellsData
|
||||||
): {burgIds: Uint16Array; stateIds: Uint16Array; burgs: TBurgs; states: TStates} {
|
): {burgIds: Uint16Array; stateIds: Uint16Array; burgs: TBurgs; states: TStates; conflicts: IConflict[]} {
|
||||||
const cellsNumber = cells.i.length;
|
const cellsNumber = cells.i.length;
|
||||||
|
|
||||||
const scoredCellIds = getScoredCellIds();
|
const scoredCellIds = getScoredCellIds();
|
||||||
|
|
@ -31,7 +31,8 @@ export function generateBurgsAndStates(
|
||||||
burgIds: new Uint16Array(cellsNumber),
|
burgIds: new Uint16Array(cellsNumber),
|
||||||
stateIds: new Uint16Array(cellsNumber),
|
stateIds: new Uint16Array(cellsNumber),
|
||||||
burgs: [NO_BURG],
|
burgs: [NO_BURG],
|
||||||
states: [NEUTRALS]
|
states: [NEUTRALS],
|
||||||
|
conflicts: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +70,9 @@ export function generateBurgsAndStates(
|
||||||
|
|
||||||
const statistics = collectStatistics({...cells, state: stateIds, burg: burgIds}, burgs);
|
const statistics = collectStatistics({...cells, state: stateIds, burg: burgIds}, burgs);
|
||||||
const diplomacy = generateRelations(statesData, statistics, pick(cells, "f"));
|
const diplomacy = generateRelations(statesData, statistics, pick(cells, "f"));
|
||||||
const states = specifyStates(statesData, statistics, diplomacy, cultures, burgs);
|
const {states, conflicts} = specifyStates(statesData, statistics, diplomacy, cultures, burgs);
|
||||||
|
|
||||||
return {burgIds, stateIds, burgs, states};
|
return {burgIds, stateIds, burgs, states, conflicts};
|
||||||
|
|
||||||
function getScoredCellIds() {
|
function getScoredCellIds() {
|
||||||
const score = new Int16Array(cells.s.map(s => s * Math.random()));
|
const score = new Int16Array(cells.s.map(s => s * Math.random()));
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,22 @@
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
|
|
||||||
import {TIME} from "config/logging";
|
import {TIME} from "config/logging";
|
||||||
import {list, trimVowels} from "utils/languageUtils";
|
import {getAdjective, list, trimVowels} from "utils/languageUtils";
|
||||||
import {gauss, ra} from "utils/probabilityUtils";
|
import {gauss, P, ra, rw} from "utils/probabilityUtils";
|
||||||
|
import {conflictTypes} from "./config";
|
||||||
|
|
||||||
export function generateConflicts(states: IState[]) {
|
const {Names} = window;
|
||||||
|
|
||||||
|
export function generateConflicts(states: IState[], cultures: TCultures): IConflict[] {
|
||||||
TIME && console.time("generateConflicts");
|
TIME && console.time("generateConflicts");
|
||||||
|
const historicalWars = generateHistoricalConflicts(states, cultures);
|
||||||
|
const ongoingWars = generateOngoingConflicts(states);
|
||||||
|
|
||||||
|
TIME && console.timeEnd("generateConflicts");
|
||||||
|
return [...historicalWars, ...ongoingWars].sort((a, b) => a.start - b.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateOngoingConflicts(states: IState[]): IConflict[] {
|
||||||
const statesMap = new Map(states.map(state => [state.i, state]));
|
const statesMap = new Map(states.map(state => [state.i, state]));
|
||||||
const wars: IConflict[] = [];
|
const wars: IConflict[] = [];
|
||||||
|
|
||||||
|
|
@ -37,7 +47,6 @@ export function generateConflicts(states: IState[]) {
|
||||||
wars.push(war);
|
wars.push(war);
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME && console.timeEnd("generateConflicts");
|
|
||||||
return wars;
|
return wars;
|
||||||
|
|
||||||
function simulateWar(attacker: IState, defender: IState): IConflict {
|
function simulateWar(attacker: IState, defender: IState): IConflict {
|
||||||
|
|
@ -134,7 +143,7 @@ export function generateConflicts(states: IState[]) {
|
||||||
const name = `${attacker.name}-${trimVowels(defender.name)}ian War`;
|
const name = `${attacker.name}-${trimVowels(defender.name)}ian War`;
|
||||||
const parties = {attackers: attackers.map(({i}) => i), defenders: defenders.map(({i}) => i)};
|
const parties = {attackers: attackers.map(({i}) => i), defenders: defenders.map(({i}) => i)};
|
||||||
const start = options.year - gauss(2, 2, 0, 5);
|
const start = options.year - gauss(2, 2, 0, 5);
|
||||||
return {type: "conflict", name, start, parties, description: history.join(". ")};
|
return {name, start, parties, description: history.join(". ")};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatePower(state: IState) {
|
function getStatePower(state: IState) {
|
||||||
|
|
@ -156,3 +165,31 @@ export function generateConflicts(states: IState[]) {
|
||||||
return "minor";
|
return "minor";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateHistoricalConflicts(states: IState[], cultures: TCultures): IConflict[] {
|
||||||
|
const statesMap = new Map(states.map(state => [state.i, state]));
|
||||||
|
const isConflict = (conflict: IConflict | null): conflict is IConflict => conflict !== null;
|
||||||
|
const getNameBase = (cultureId: number) => cultures[cultureId].base;
|
||||||
|
return states.map(generateConflicts).flat();
|
||||||
|
|
||||||
|
function generateConflicts(state: IState): IConflict[] {
|
||||||
|
const conflicts = state.neighbors
|
||||||
|
.map((neighbor, index) => {
|
||||||
|
if (index && P(0.8)) return null;
|
||||||
|
const enemy = statesMap.get(neighbor);
|
||||||
|
if (!enemy) return null;
|
||||||
|
|
||||||
|
const properName = P(0.8) ? enemy.name : Names.getBaseShort(getNameBase(enemy.culture));
|
||||||
|
const name = getAdjective(properName) + " " + rw(conflictTypes);
|
||||||
|
const start = gauss(options.year - 100, 150, 1, options.year - 6);
|
||||||
|
const end = start + gauss(4, 5, 1, options.year - start - 1);
|
||||||
|
const parties = {attackers: [state.i], defenders: [enemy.i]};
|
||||||
|
|
||||||
|
const conflict: IConflict = {name, start, end, parties};
|
||||||
|
return conflict;
|
||||||
|
})
|
||||||
|
.filter(isConflict);
|
||||||
|
|
||||||
|
return conflicts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function specifyStates(
|
||||||
diplomacy: TDiplomacy,
|
diplomacy: TDiplomacy,
|
||||||
cultures: TCultures,
|
cultures: TCultures,
|
||||||
burgs: TBurgs
|
burgs: TBurgs
|
||||||
): TStates {
|
): {states: TStates; conflicts: IConflict[]} {
|
||||||
TIME && console.time("specifyStates");
|
TIME && console.time("specifyStates");
|
||||||
|
|
||||||
const colors = defineStateColors(statistics);
|
const colors = defineStateColors(statistics);
|
||||||
|
|
@ -56,10 +56,8 @@ export function specifyStates(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const wars = generateConflicts(states); // mutates states
|
const conflicts = generateConflicts(states, cultures); // mutates states
|
||||||
console.log(wars);
|
|
||||||
console.log(states);
|
|
||||||
|
|
||||||
TIME && console.timeEnd("specifyStates");
|
TIME && console.timeEnd("specifyStates");
|
||||||
return [NEUTRALS, ...states];
|
return {states: [NEUTRALS, ...states], conflicts};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {generateReligions} from "./religions/generateReligions";
|
||||||
const {LAND_COAST, WATER_COAST, DEEPER_WATER} = DISTANCE_FIELD;
|
const {LAND_COAST, WATER_COAST, DEEPER_WATER} = DISTANCE_FIELD;
|
||||||
const {Biomes} = window;
|
const {Biomes} = window;
|
||||||
|
|
||||||
export function createPack(grid: IGrid): IPack {
|
export function createPack(grid: IGrid): {pack: IPack; conflicts: IConflict[]} {
|
||||||
const {temp, prec} = grid.cells;
|
const {temp, prec} = grid.cells;
|
||||||
const {vertices, cells} = repackGrid(grid);
|
const {vertices, cells} = repackGrid(grid);
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ export function createPack(grid: IGrid): IPack {
|
||||||
pop: population
|
pop: population
|
||||||
});
|
});
|
||||||
|
|
||||||
const {burgIds, stateIds, burgs, states} = generateBurgsAndStates(
|
const {burgIds, stateIds, burgs, states, conflicts} = generateBurgsAndStates(
|
||||||
cultures,
|
cultures,
|
||||||
mergedFeatures,
|
mergedFeatures,
|
||||||
temp,
|
temp,
|
||||||
|
|
@ -199,7 +199,7 @@ export function createPack(grid: IGrid): IPack {
|
||||||
religions
|
religions
|
||||||
};
|
};
|
||||||
|
|
||||||
return pack;
|
return {pack, conflicts};
|
||||||
}
|
}
|
||||||
|
|
||||||
// repack grid cells: discart deep water cells, add land cells along the coast
|
// repack grid cells: discart deep water cells, add land cells along the coast
|
||||||
|
|
|
||||||
8
src/types/events.d.ts
vendored
8
src/types/events.d.ts
vendored
|
|
@ -1,13 +1,15 @@
|
||||||
|
interface IEvents {
|
||||||
|
conflicts: IConflict[];
|
||||||
|
}
|
||||||
|
|
||||||
interface IEvent {
|
interface IEvent {
|
||||||
type: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
start: number;
|
start: number;
|
||||||
end?: number; // undefined for ongoing events
|
end?: number; // undefined for ongoing events
|
||||||
description: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IConflict extends IEvent {
|
interface IConflict extends IEvent {
|
||||||
type: "conflict";
|
|
||||||
parties: {
|
parties: {
|
||||||
attackers: number[];
|
attackers: number[];
|
||||||
defenders: number[];
|
defenders: number[];
|
||||||
|
|
|
||||||
4
src/types/globals.d.ts
vendored
4
src/types/globals.d.ts
vendored
|
|
@ -1,11 +1,13 @@
|
||||||
declare let grid: IGrid;
|
declare let grid: IGrid;
|
||||||
declare let pack: IPack;
|
declare let pack: IPack;
|
||||||
|
|
||||||
|
declare let notes: INote[];
|
||||||
|
declare let events: IEvents;
|
||||||
|
|
||||||
declare let seed: string;
|
declare let seed: string;
|
||||||
declare let mapId: number;
|
declare let mapId: number;
|
||||||
declare let mapHistory: IMapHistoryEntry[];
|
declare let mapHistory: IMapHistoryEntry[];
|
||||||
|
|
||||||
declare let notes: INote[];
|
|
||||||
declare let customization: number;
|
declare let customization: number;
|
||||||
|
|
||||||
declare let rulers: Rulers;
|
declare let rulers: Rulers;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue