diff --git a/heightmaps/import-rules.txt b/heightmaps/import-rules.txt index 9478b35c..69499114 100644 --- a/heightmaps/import-rules.txt +++ b/heightmaps/import-rules.txt @@ -1,8 +1,8 @@ To get heightmap with correct height scale: -1. Open tangrams.github.io +1. Open https://tangrams.github.io/heightmapper 2. Toggle off auto-exposure 3. Set max elevation to 2000 4. Set min elevation to -500 5. Find region you like 6. Render image -7. Optionally rescale image to a smaller size (e.g. 500x300px) as high resolution is not used \ No newline at end of file +7. Optionally rescale image to a smaller size (e.g. 500x300px) as high resolution is not used diff --git a/index.html b/index.html index cb428e3a..ce7f00e2 100644 --- a/index.html +++ b/index.html @@ -7863,14 +7863,14 @@ - + - + diff --git a/main.js b/main.js index d3b290b8..5f9086f6 100644 --- a/main.js +++ b/main.js @@ -191,7 +191,6 @@ let populationRate = +document.getElementById("populationRateInput").value; let distanceScale = +document.getElementById("distanceScaleInput").value; let urbanization = +document.getElementById("urbanizationInput").value; let urbanDensity = +document.getElementById("urbanDensityInput").value; -let statesNeutral = 1; // statesEditor growth parameter applyStoredOptions(); diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index e9069e83..e360b45a 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -359,7 +359,7 @@ window.BurgsAndStates = (function () { TIME && console.timeEnd("drawBurgs"); }; - // growth algorithm to assign cells to states like we did for cultures + // expand cultures across the map (Dijkstra-like algorithm) const expandStates = function () { TIME && console.time("expandStates"); const {cells, states, cultures, burgs} = pack; @@ -367,18 +367,28 @@ window.BurgsAndStates = (function () { cells.state = cells.state || new Uint16Array(cells.i.length); const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); const cost = []; - const neutral = (cells.i.length / 5000) * 2500 * neutralInput.value * statesNeutral; // limit cost for state growth - states - .filter(s => s.i && !s.removed) - .forEach(s => { - const capitalCell = burgs[s.capital].cell; - cells.state[capitalCell] = s.i; - const cultureCenter = cultures[s.culture].center; - const b = cells.biome[cultureCenter]; // state native biome - queue.queue({e: s.center, p: 0, s: s.i, b}); - cost[s.center] = 1; - }); + const globalNeutralRate = byId("neutralInput")?.valueAsNumber || 1; + const statesNeutralRate = byId("statesNeutral")?.valueAsNumber || 1; + const neutral = (cells.i.length / 2) * globalNeutralRate * statesNeutralRate; // limit cost for state growth + + // remove state from all cells except of locked + for (const cellId of cells.i) { + const state = states[cells.state[cellId]]; + if (state.lock) continue; + cells.state[cellId] = 0; + } + + for (const state of states) { + if (!state.i || state.removed) continue; + + const capitalCell = burgs[state.capital].cell; + cells.state[capitalCell] = state.i; + const cultureCenter = cultures[state.culture].center; + const b = cells.biome[cultureCenter]; // state native biome + queue.queue({e: state.center, p: 0, s: state.i, b}); + cost[state.center] = 1; + } while (queue.length) { const next = queue.dequeue(); diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index db8fb06a..cb8473ca 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -116,10 +116,10 @@ window.Cultures = (function () { cultures.forEach(c => (c.base = c.base % nameBases.length)); - function selectCultures(c) { - let def = getDefault(c); + function selectCultures(culturesNumber) { + let def = getDefault(culturesNumber); const cultures = []; - + pack.cultures?.forEach(function (culture) { if (culture.lock) cultures.push(culture); }); @@ -153,8 +153,8 @@ window.Cultures = (function () { } } } else { - if (c === def.length) return def; - if (def.every(d => d.odd === 1)) return def.splice(0, c); + if (culturesNumber === def.length) return def; + if (def.every(d => d.odd === 1)) return def.splice(0, culturesNumber); if (pack.religions?.length > 2) { pack.religions.forEach(r => { if (r.type === "Folk" && !r.lock) r.removed = true; @@ -162,7 +162,7 @@ window.Cultures = (function () { } } - for (let culture, rnd, i = 0; cultures.length < c && def.length > 0;) { + for (let culture, rnd, i = 0; cultures.length < culturesNumber && def.length > 0;) { do { rnd = rand(def.length - 1); culture = def[rnd]; @@ -542,28 +542,37 @@ window.Cultures = (function () { // expand cultures across the map (Dijkstra-like algorithm) const expand = function () { TIME && console.time("expandCultures"); - cells = pack.cells; + const {cells, cultures} = pack; const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); - pack.cultures.forEach(function (c) { - if (!c.i || c.removed || c.lock) return; - queue.queue({e: c.center, p: 0, c: c.i}); - }); - - const neutral = (cells.i.length / 5000) * 3000 * neutralInput.value; // limit cost for culture growth const cost = []; + + const neutralRate = byId("neutralRate")?.valueAsNumber || 1; + const neutral = cells.i.length * 0.6 * neutralRate; // limit cost for culture growth + + // remove culture from all cells except of locked + for (const cellId of cells.i) { + const culture = cultures[cells.culture[cellId]]; + if (culture.lock) continue; + cells.culture[cellId] = 0; + } + + for (const culture of cultures) { + if (!culture.i || culture.removed) continue; + queue.queue({e: culture.center, p: 0, c: culture.i}); + } + while (queue.length) { - const next = queue.dequeue(), - n = next.e, - p = next.p, - c = next.c; - const type = pack.cultures[c].type; - cells.c[n].forEach(e => { - if (pack.cultures[cells.culture[e]]?.lock) return; + const {e, p, c} = queue.dequeue(); + const {type} = pack.cultures[c]; + + cells.c[e].forEach(e => { + const culture = cells.culture[e]; + if (culture?.lock) return; // do not overwrite cell of locked culture const biome = cells.biome[e]; const biomeCost = getBiomeCost(c, biome, type); - const biomeChangeCost = biome === cells.biome[n] ? 0 : 20; // penalty on biome change + const biomeChangeCost = biome === cells.biome[e] ? 0 : 20; // penalty on biome change const heightCost = getHeightCost(e, cells.h[e], type); const riverCost = getRiverCost(cells.r[e], e, type); const typeCost = getTypeCost(cells.t[e], type); diff --git a/modules/dynamic/editors/states-editor.js b/modules/dynamic/editors/states-editor.js index 87592706..41241340 100644 --- a/modules/dynamic/editors/states-editor.js +++ b/modules/dynamic/editors/states-editor.js @@ -883,7 +883,6 @@ function changeStatesGrowthRate() { const growthRate = +this.value; byId("statesNeutral").value = growthRate; byId("statesNeutralNumber").value = growthRate; - statesNeutral = growthRate; tip("Growth rate: " + growthRate); recalculateStates(false); } diff --git a/modules/religions-generator.js b/modules/religions-generator.js index 44426f59..010dec5e 100644 --- a/modules/religions-generator.js +++ b/modules/religions-generator.js @@ -351,9 +351,8 @@ window.Religions = (function () { const codes = []; // add folk religions - pack.cultures.forEach(c => { - const newId = c.i; - if (!newId) return religions.push({i: 0, name: "No religion"}); + cultures.forEach(c => { + if (!c.i) return religions.push({i: 0, name: "No religion"}); if (c.removed) { religions.push({ @@ -365,6 +364,8 @@ window.Religions = (function () { return; } + const newId = c.i; + if (pack.religions) { const lockedFolkReligion = pack.religions.find( r => r.culture === c.i && !r.removed && r.lock && r.type === "Folk" @@ -868,7 +869,6 @@ window.Religions = (function () { r.culture = cells.culture[r.center]; } }); - TIME && console.timeEnd("updateCulturesForReligions"); } // get supreme deity name diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 2fb4db07..def092fe 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -1176,7 +1176,7 @@ function refreshAllEditors() { // dynamically loaded editors async function editStates() { if (customization) return; - const Editor = await import("../dynamic/editors/states-editor.js?v=1.89.02"); + const Editor = await import("../dynamic/editors/states-editor.js?v=1.89.05"); Editor.open(); } diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 07216f90..bd41cefe 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -204,6 +204,13 @@ function editHeightmap(options) { INFO && console.group("Edit Heightmap"); TIME && console.time("regenerateErasedData"); + // remove data + pack.cultures = []; + pack.burgs = []; + pack.states = []; + pack.provinces = []; + pack.religions = []; + const erosionAllowed = allowErosion.checked; markFeatures(); markupGridOcean(); @@ -231,8 +238,10 @@ function editHeightmap(options) { Lakes.defineGroup(); defineBiomes(); rankCells(); + Cultures.generate(); Cultures.expand(); + BurgsAndStates.generate(); Religions.generate(); BurgsAndStates.defineStateForms();