Merge branch 'master' of https://github.com/Azgaar/Fantasy-Map-Generator into hierarchy-tree-better-control

This commit is contained in:
Azgaar 2022-06-12 15:45:39 +03:00
commit f723bb4fba
4 changed files with 102 additions and 55 deletions

View file

@ -7821,7 +7821,7 @@
<script defer src="modules/relief-icons.js"></script> <script defer src="modules/relief-icons.js"></script>
<script defer src="modules/ui/style.js"></script> <script defer src="modules/ui/style.js"></script>
<script defer src="modules/ui/editors.js?v=080620222"></script> <script defer src="modules/ui/editors.js?v=080620222"></script>
<script defer src="modules/ui/tools.js?v=01062022"></script> <script defer src="modules/ui/tools.js?v=12062022"></script>
<script defer src="modules/ui/world-configurator.js?v=29052022"></script> <script defer src="modules/ui/world-configurator.js?v=29052022"></script>
<script defer src="modules/ui/heightmap-editor.js?v=29052020"></script> <script defer src="modules/ui/heightmap-editor.js?v=29052020"></script>
<script defer src="modules/ui/provinces-editor.js?v=29052022"></script> <script defer src="modules/ui/provinces-editor.js?v=29052022"></script>
@ -7859,7 +7859,7 @@
<script defer src="libs/jquery.ui.touch-punch.min.js"></script> <script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="modules/io/save.js?v=29052022"></script> <script defer src="modules/io/save.js?v=29052022"></script>
<script defer src="modules/io/load.js?v=01062022"></script> <script defer src="modules/io/load.js?v=12062022"></script>
<script defer src="modules/io/cloud.js?v=04062022"></script> <script defer src="modules/io/cloud.js?v=04062022"></script>
<script defer src="modules/io/export.js?v=04062022"></script> <script defer src="modules/io/export.js?v=04062022"></script>
<script defer src="modules/io/formats.js"></script> <script defer src="modules/io/formats.js"></script>

View file

@ -28,8 +28,7 @@ async function createSharableDropboxLink() {
try { try {
url = await Cloud.providers.dropbox.getLink(mapFile); url = await Cloud.providers.dropbox.getLink(mapFile);
} catch { } catch {
tip("Dropbox API error. Can not create link.", true, "error", 2000); return tip("Dropbox API error. Can not create link.", true, "error", 2000);
return;
} }
const fmg = window.location.href.split("?")[0]; const fmg = window.location.href.split("?")[0];
@ -500,23 +499,28 @@ async function parseLoadedData(data) {
ERROR && console.error("Data Integrity Check. Invalid river", r, "is assigned to cells", invalidCells); ERROR && console.error("Data Integrity Check. Invalid river", r, "is assigned to cells", invalidCells);
}); });
pack.burgs.forEach(b => { pack.burgs.forEach(burg => {
if (!b.i || b.removed) return; if (!burg.i || burg.removed) return;
if (b.port < 0) { if (burg.port < 0) {
ERROR && console.error("Data Integrity Check. Burg", b.i, "has invalid port value", b.port); ERROR && console.error("Data Integrity Check. Burg", burg.i, "has invalid port value", burg.port);
b.port = 0; burg.port = 0;
} }
if (b.cell >= cells.i.length) { if (burg.cell >= cells.i.length) {
ERROR && console.error("Data Integrity Check. Burg", b.i, "is linked to invalid cell", b.cell); ERROR && console.error("Data Integrity Check. Burg", burg.i, "is linked to invalid cell", burg.cell);
b.cell = findCell(b.x, b.y); burg.cell = findCell(burg.x, burg.y);
cells.i.filter(i => cells.burg[i] === b.i).forEach(i => (cells.burg[i] = 0)); cells.i.filter(i => cells.burg[i] === burg.i).forEach(i => (cells.burg[i] = 0));
cells.burg[b.cell] = b.i; cells.burg[burg.cell] = burg.i;
} }
if (b.state && !pack.states[b.state]) { if (burg.state && !pack.states[burg.state]) {
ERROR && console.error("Data Integrity Check. Burg", b.i, "is linked to invalid state", b.state); ERROR && console.error("Data Integrity Check. Burg", burg.i, "is linked to invalid state", burg.state);
b.state = 0; burg.state = 0;
}
if (burg.state === undefined) {
ERROR && console.error("Data Integrity Check. Burg", burg.i, "has no state data");
burg.state = 0;
} }
}); });

View file

@ -143,7 +143,8 @@ function regenerateStates() {
const statesCount = +regionsOutput.value; const statesCount = +regionsOutput.value;
const burgs = pack.burgs.filter(b => b.i && !b.removed); const burgs = pack.burgs.filter(b => b.i && !b.removed);
if (!burgs.length) return tip("There are no any burgs to generate states. Please create burgs first", false, "error"); if (!burgs.length) return tip("There are no any burgs to generate states. Please create burgs first", false, "error");
if (burgs.length < statesCount) tip(`Not enough burgs to generate ${statesCount} states. Will generate only ${burgs.length} states`, false, "warn"); if (burgs.length < statesCount)
tip(`Not enough burgs to generate ${statesCount} states. Will generate only ${burgs.length} states`, false, "warn");
// turn all old capitals into towns // turn all old capitals into towns
burgs burgs
@ -205,10 +206,15 @@ function regenerateStates() {
} }
const culture = capital.culture; const culture = capital.culture;
const basename = capital.name.length < 9 && capital.cell % 5 === 0 ? capital.name : Names.getCulture(culture, 3, 6, "", 0); const basename =
capital.name.length < 9 && capital.cell % 5 === 0 ? capital.name : Names.getCulture(culture, 3, 6, "", 0);
const name = Names.getState(basename, culture); const name = Names.getState(basename, culture);
const nomadic = [1, 2, 3, 4].includes(pack.cells.biome[capital.cell]); const nomadic = [1, 2, 3, 4].includes(pack.cells.biome[capital.cell]);
const type = nomadic ? "Nomadic" : pack.cultures[culture].type === "Nomadic" ? "Generic" : pack.cultures[culture].type; const type = nomadic
? "Nomadic"
: pack.cultures[culture].type === "Nomadic"
? "Generic"
: pack.cultures[culture].type;
const expansionism = rn(Math.random() * powerInput.value + 1, 1); const expansionism = rn(Math.random() * powerInput.value + 1, 1);
const cultureType = pack.cultures[culture].type; const cultureType = pack.cultures[culture].type;
@ -253,57 +259,59 @@ function regenerateProvinces() {
} }
function regenerateBurgs() { function regenerateBurgs() {
const cells = pack.cells, const {cells, states} = pack;
states = pack.states, const lockedburgs = pack.burgs.filter(b => b.lock);
Lockedburgs = pack.burgs.filter(b => b.lock);
rankCells(); rankCells();
cells.burg = new Uint16Array(cells.i.length); cells.burg = new Uint16Array(cells.i.length);
const burgs = (pack.burgs = [0]); // clear burgs array const burgs = (pack.burgs = [0]); // clear burgs array
states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals
pack.provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals pack.provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals
const burgsTree = d3.quadtree(); const burgsTree = d3.quadtree();
// add locked burgs
for (let j = 0; j < lockedburgs.length; j++) {
const id = burgs.length;
const lockedBurg = lockedburgs[j];
lockedBurg.i = id;
burgs.push(lockedBurg);
burgsTree.add([lockedBurg.x, lockedBurg.y]);
cells.burg[lockedBurg.cell] = id;
if (lockedBurg.capital) {
const stateId = lockedBurg.state;
states[stateId].capital = id;
states[stateId].center = lockedBurg.cell;
}
}
const score = new Int16Array(cells.s.map(s => s * Math.random())); // cell score for capitals placement const score = new Int16Array(cells.s.map(s => s * Math.random())); // cell score for capitals placement
const sorted = cells.i.filter(i => score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes const sorted = cells.i.filter(i => score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes
const burgsCount = const burgsCount =
manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length : +manorsInput.value + states.length; manorsInput.value === "1000"
? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length
: +manorsInput.value + states.length;
const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns
//clear locked list since ids will change
//burglock.selectAll("text").remove();
for (let j = 0; j < Lockedburgs.length; j++) {
const id = burgs.length;
const oldBurg = Lockedburgs[j];
oldBurg.i = id;
burgs.push(oldBurg);
burgsTree.add([oldBurg.x, oldBurg.y]);
cells.burg[oldBurg.cell] = id;
if (oldBurg.capital) {
states[oldBurg.state].capital = id;
states[oldBurg.state].center = oldBurg.cell;
}
//burglock.append("text").attr("data-id", id);
}
for (let i = 0; i < sorted.length && burgs.length < burgsCount; i++) { for (let i = 0; i < sorted.length && burgs.length < burgsCount; i++) {
const id = burgs.length; const id = burgs.length;
const cell = sorted[i]; const cell = sorted[i];
const x = cells.p[cell][0], const [x, y] = cells.p[cell];
y = cells.p[cell][1];
const s = spacing * gauss(1, 0.3, 0.2, 2, 2); // randomize to make the placement not uniform const s = spacing * gauss(1, 0.3, 0.2, 2, 2); // randomize to make the placement not uniform
if (burgsTree.find(x, y, s) !== undefined) continue; // to close to existing burg if (burgsTree.find(x, y, s) !== undefined) continue; // to close to existing burg
const state = cells.state[cell]; const stateId = cells.state[cell];
const capital = state && !states[state].capital; // if state doesn't have capital, make this burg a capital, no capital for neutral lands const capital = stateId && !states[stateId].capital; // if state doesn't have capital, make this burg a capital, no capital for neutral lands
if (capital) { if (capital) {
states[state].capital = id; states[stateId].capital = id;
states[state].center = cell; states[stateId].center = cell;
} }
const culture = cells.culture[cell]; const culture = cells.culture[cell];
const name = Names.getCulture(culture); const name = Names.getCulture(culture);
burgs.push({cell, x, y, state, i: id, culture, name, capital, feature: cells.f[cell]}); burgs.push({cell, x, y, state: stateId, i: id, culture, name, capital, feature: cells.f[cell]});
burgsTree.add([x, y]); burgsTree.add([x, y]);
cells.burg[cell] = id; cells.burg[cell] = id;
} }
@ -321,8 +329,9 @@ function regenerateBurgs() {
}); });
pack.features.forEach(f => { pack.features.forEach(f => {
if (f.port) f.port = 0; if (f.port) f.port = 0; // reset features ports counter
}); // reset features ports counter });
BurgsAndStates.specifyBurgs(); BurgsAndStates.specifyBurgs();
BurgsAndStates.defineBurgFeatures(); BurgsAndStates.defineBurgFeatures();
BurgsAndStates.drawBurgs(); BurgsAndStates.drawBurgs();
@ -425,7 +434,10 @@ function regenerateMarkers() {
} }
function regenerateZones(event) { function regenerateZones(event) {
if (isCtrlClick(event)) prompt("Please provide zones number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v => addNumberOfZones(v)); if (isCtrlClick(event))
prompt("Please provide zones number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v =>
addNumberOfZones(v)
);
else addNumberOfZones(gauss(1, 0.5, 0.6, 5, 2)); else addNumberOfZones(gauss(1, 0.5, 0.6, 5, 2));
function addNumberOfZones(number) { function addNumberOfZones(number) {
@ -542,7 +554,18 @@ function addRiverOnClick() {
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error"); if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
if (cells.b[i]) return; if (cells.b[i]) return;
const {alterHeights, resolveDepressions, addMeandering, getRiverPath, getBasin, getName, getType, getWidth, getOffset, getApproximateLength} = Rivers; const {
alterHeights,
resolveDepressions,
addMeandering,
getRiverPath,
getBasin,
getName,
getType,
getWidth,
getOffset,
getApproximateLength
} = Rivers;
const riverCells = []; const riverCells = [];
let riverId = rivers.length ? last(rivers).i + 1 : 1; let riverId = rivers.length ? last(rivers).i + 1 : 1;
let parent = riverId; let parent = riverId;
@ -623,7 +646,8 @@ function addRiverOnClick() {
const mouth = riverCells[riverCells.length - 2]; const mouth = riverCells[riverCells.length - 2];
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2); const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
const widthFactor = river?.widthFactor || (!parent || parent === riverId ? defaultWidthFactor * 1.2 : defaultWidthFactor); const widthFactor =
river?.widthFactor || (!parent || parent === riverId ? defaultWidthFactor * 1.2 : defaultWidthFactor);
const meanderedPoints = addMeandering(riverCells); const meanderedPoints = addMeandering(riverCells);
const discharge = cells.fl[mouth]; // m3 in second const discharge = cells.fl[mouth]; // m3 in second
@ -641,7 +665,21 @@ function addRiverOnClick() {
const name = getName(mouth); const name = getName(mouth);
const type = getType({i: riverId, length, parent}); const type = getType({i: riverId, length, parent});
rivers.push({i: riverId, source, mouth, discharge, length, width, widthFactor, sourceWidth: 0, parent, cells: riverCells, basin, name, type}); rivers.push({
i: riverId,
source,
mouth,
discharge,
length,
width,
widthFactor,
sourceWidth: 0,
parent,
cells: riverCells,
basin,
name,
type
});
} }
// render river // render river
@ -678,7 +716,12 @@ function addRouteOnClick() {
unpressClickToAddButton(); unpressClickToAddButton();
const point = d3.mouse(this); const point = d3.mouse(this);
const id = getNextId("route"); const id = getNextId("route");
elSelected = routes.select("g").append("path").attr("id", id).attr("data-new", 1).attr("d", `M${point[0]},${point[1]}`); elSelected = routes
.select("g")
.append("path")
.attr("id", id)
.attr("data-new", 1)
.attr("d", `M${point[0]},${point[1]}`);
editRoute(true); editRoute(true);
} }

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
// version and caching control // version and caching control
const version = "1.86.04"; // generator version, update each time const version = "1.86.05"; // generator version, update each time
{ {
document.title += " v" + version; document.title += " v" + version;