mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
v 0.8.14b
This commit is contained in:
parent
edc3fc1826
commit
f81fd8a94c
8 changed files with 100 additions and 41 deletions
|
|
@ -378,6 +378,11 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
|||
font-size: smaller;
|
||||
}
|
||||
|
||||
#optionsContent output {
|
||||
text-align: right;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#optionsContent input[type="number"] {
|
||||
border: 0;
|
||||
text-align: right;
|
||||
|
|
|
|||
20
index.html
20
index.html
|
|
@ -807,14 +807,14 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr data-tip="Cells density controls underlying graph size and hightly affects performance">
|
||||
<tr data-tip="Set number of points to be used for graph generation. Highly affects performance">
|
||||
<td></td>
|
||||
<td>Cells density</td>
|
||||
<td>Points number</td>
|
||||
<td>
|
||||
<input id="densityInput" type="range" min=1 max=3 value=1>
|
||||
<input id="densityInput" type="range" min=1 max=10 value=1>
|
||||
</td>
|
||||
<td>
|
||||
<input id="densityOutput" type="number" min=1 max=3 value=1>
|
||||
<output id="densityOutput">10K</output>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
|
@ -852,7 +852,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr data-tip="Define how many States should be generated">
|
||||
<tr data-tip="Define how many states and capitals should be generated">
|
||||
<td>
|
||||
<i data-locked=0 id="lock_regions" class="icon-lock-open"></i>
|
||||
</td>
|
||||
|
|
@ -865,7 +865,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr data-tip="Define how much states and cultures size can vary. Defines expansionism value">
|
||||
<tr data-tip="Define how much states and cultures can vary in size. Defines expansionism value">
|
||||
<td>
|
||||
<i data-locked=0 id="lock_power" class="icon-lock-open"></i>
|
||||
</td>
|
||||
|
|
@ -891,16 +891,16 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr data-tip="Define how densely settled areas (burgs) should be placed">
|
||||
<tr data-tip="Define how many towns (non-capital burgs) should be generated">
|
||||
<td>
|
||||
<i data-locked=0 id="lock_manors" class="icon-lock-open"></i>
|
||||
</td>
|
||||
<td>Burgs density</td>
|
||||
<td>Towns number</td>
|
||||
<td>
|
||||
<input id="manorsInput" data-stored="manors" type="range" min=0.1 max=5 step=.1 value=1>
|
||||
<input id="manorsInput" data-stored="manors" type="range" min=0 max=1000 step=1 value=1000>
|
||||
</td>
|
||||
<td>
|
||||
<input id="manorsOutput" data-stored="manors" type="number" min=0.1 max=5 step=.1 value=1>
|
||||
<output id="manorsOutput" data-stored="manors" value="auto"></output>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
|
|
|||
4
main.js
4
main.js
|
|
@ -1153,7 +1153,7 @@ function showStatistics() {
|
|||
console.log(stats);
|
||||
}
|
||||
|
||||
function regenerateMap() {
|
||||
const regenerateMap = debounce(function() {
|
||||
closeDialogs("#worldConfigurator");
|
||||
customization = 0;
|
||||
undraw();
|
||||
|
|
@ -1161,7 +1161,7 @@ function regenerateMap() {
|
|||
generate();
|
||||
restoreLayers();
|
||||
if ($("#worldConfigurator").is(":visible")) editWorld();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Clear the map
|
||||
function undraw() {
|
||||
|
|
|
|||
|
|
@ -106,12 +106,12 @@
|
|||
const score = new Int16Array(cells.s.map(s => s * Math.random())); // cell score for towns 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
|
||||
|
||||
// burgs number depends on ratio between populated and all cells and burgsDensity input (expected mean ~300))
|
||||
const burgsCount = rn(sorted.length / grid.points.length * manorsInput.value * 1000);
|
||||
let burgsCount = manorsInput.value == 1000 ? rn(sorted.length / 10 / densityInput.value ** .8) : +manorsInput.value;
|
||||
burgsCount += burgs.length;
|
||||
const spacing = (graphWidth + graphHeight) * 9 / burgsCount; // base min distance between towns
|
||||
const burgsTree = burgs[0];
|
||||
|
||||
for (let i = 0; burgs.length <= burgsCount && i < sorted.length; i++) {
|
||||
for (let i = 0; burgs.length < burgsCount && i < sorted.length; i++) {
|
||||
const id = sorted[i], x = cells.p[id][0], y = cells.p[id][1];
|
||||
const s = spacing * Math.random() + 0.5; // randomize to make the placement not uniform
|
||||
if (burgsTree.find(x, y, s) !== undefined) continue; // to close to existing burg
|
||||
|
|
@ -124,7 +124,7 @@
|
|||
cells.burg[id] = burg;
|
||||
}
|
||||
|
||||
if (burgs.length <= burgsCount) console.error(`Cannot place all burgs. Requested ${burgsCount}, placed ${burgs.length-1}`);
|
||||
if (burgs.length < burgsCount) console.error(`Cannot place all burgs. Requested ${burgsCount}, placed ${burgs.length-1}`);
|
||||
|
||||
//const min = d3.min(score.filter(s => s)), max = d3.max(score);
|
||||
//terrs.selectAll("polygon").data(sorted).enter().append("polygon").attr("points", d => getPackPolygon(d)).attr("fill", d => color(1 - normalize(score[d], min, max)));
|
||||
|
|
|
|||
|
|
@ -174,9 +174,40 @@
|
|||
addStep("Trough", "3-4", "25-35", "5-95", "80-90");
|
||||
addStep("Range", "5-6", "30-40", "10-90", "35-65");
|
||||
}
|
||||
|
||||
function getBlobPower() {
|
||||
switch (+densityInput.value) {
|
||||
case 1: return .98;
|
||||
case 2: return .985;
|
||||
case 3: return .987;
|
||||
case 4: return .9892;
|
||||
case 5: return .9911;
|
||||
case 6: return .9921;
|
||||
case 7: return .9934;
|
||||
case 8: return .9942;
|
||||
case 9: return .9946;
|
||||
case 10: return .995;
|
||||
}
|
||||
}
|
||||
|
||||
function getLinePower() {
|
||||
switch (+densityInput.value) {
|
||||
case 1: return .81;
|
||||
case 2: return .82;
|
||||
case 3: return .83;
|
||||
case 4: return .84;
|
||||
case 5: return .855;
|
||||
case 6: return .87;
|
||||
case 7: return .885;
|
||||
case 8: return .91;
|
||||
case 9: return .92;
|
||||
case 10: return .93;
|
||||
}
|
||||
}
|
||||
|
||||
const addHill = function(count, height, rangeX, rangeY) {
|
||||
count = getNumberInRange(count);
|
||||
const power = getBlobPower();
|
||||
while (count >= 1 || Math.random() < count) {addOneHill(); count--;}
|
||||
|
||||
function addOneHill() {
|
||||
|
|
@ -198,7 +229,7 @@
|
|||
|
||||
for (const c of cells.c[q]) {
|
||||
if (change[c]) continue;
|
||||
change[c] = change[q] ** .98 * (Math.random() * .2 + .9);
|
||||
change[c] = change[q] ** power * (Math.random() * .2 + .9);
|
||||
if (change[c] > 1) queue.push(c);
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +258,7 @@
|
|||
const queue = [start];
|
||||
while (queue.length) {
|
||||
const q = queue.shift();
|
||||
h = h ** .98 * (Math.random() * .2 + .9);
|
||||
h = h ** getBlobPower() * (Math.random() * .2 + .9);
|
||||
if (h < 1) return;
|
||||
|
||||
cells.c[q].forEach(function(c, i) {
|
||||
|
|
@ -242,13 +273,14 @@
|
|||
|
||||
const addRange = function(count, height, rangeX, rangeY) {
|
||||
count = getNumberInRange(count);
|
||||
while (count >= 1 || Math.random() < count) {addOneRange(); count--;}
|
||||
const power = getLinePower();
|
||||
while (count >= 1 || Math.random() < count) {addOneRange(); count--;}
|
||||
|
||||
function addOneRange() {
|
||||
const used = new Uint8Array(cells.h.length);
|
||||
let h = lim(getNumberInRange(height));
|
||||
|
||||
// find start and end points
|
||||
// find start and end points
|
||||
const startX = getPointInRange(rangeX, graphWidth);
|
||||
const startY = getPointInRange(rangeY, graphHeight);
|
||||
|
||||
|
|
@ -260,7 +292,7 @@
|
|||
limit++;
|
||||
} while ((dist < graphWidth / 8 || dist > graphWidth / 3) && limit < 50)
|
||||
|
||||
let range = getRange(findGridCell(startX, startY), findGridCell(endX, endY));
|
||||
let range = getRange(findGridCell(startX, startY), findGridCell(endX, endY));
|
||||
|
||||
// get main ridge
|
||||
function getRange(cur, end) {
|
||||
|
|
@ -291,11 +323,11 @@
|
|||
frontier.forEach(i => {
|
||||
cells.h[i] = lim(cells.h[i] + h * (Math.random() * .3 + .85));
|
||||
});
|
||||
h = h ** .82 - 1;
|
||||
h = h ** power - 1;
|
||||
if (h < 2) break;
|
||||
frontier.forEach(f => {
|
||||
cells.c[f].forEach(i => {
|
||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -316,13 +348,14 @@
|
|||
|
||||
const addTrough = function(count, height, rangeX, rangeY) {
|
||||
count = getNumberInRange(count);
|
||||
while (count >= 1 || Math.random() < count) {addOneTrough(); count--;}
|
||||
const power = getLinePower();
|
||||
while (count >= 1 || Math.random() < count) {addOneTrough(); count--;}
|
||||
|
||||
function addOneTrough() {
|
||||
const used = new Uint8Array(cells.h.length);
|
||||
let h = lim(getNumberInRange(height));
|
||||
|
||||
// find start and end points
|
||||
// find start and end points
|
||||
let limit = 0, startX, startY, start, dist = 0, endX, endY;
|
||||
do {
|
||||
startX = getPointInRange(rangeX, graphWidth);
|
||||
|
|
@ -370,11 +403,11 @@
|
|||
frontier.forEach(i => {
|
||||
cells.h[i] = lim(cells.h[i] - h * (Math.random() * .3 + .85));
|
||||
});
|
||||
h = h ** .8 - 1;
|
||||
h = h ** power - 1;
|
||||
if (h < 2) break;
|
||||
frontier.forEach(f => {
|
||||
cells.c[f].forEach(i => {
|
||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -405,7 +438,7 @@
|
|||
|
||||
const start = findGridCell(startX, startY), end = findGridCell(endX, endY);
|
||||
let range = getRange(start, end);
|
||||
const query = [];
|
||||
const query = [];
|
||||
|
||||
function getRange(cur, end) {
|
||||
const range = [];
|
||||
|
|
|
|||
|
|
@ -77,10 +77,11 @@ function showMapTooltip(e, i, g) {
|
|||
tip(""); // clear tip
|
||||
const tag = e.target.tagName;
|
||||
const path = e.composedPath ? e.composedPath() : getComposedPath(e.target); // apply polyfill
|
||||
if (!path[path.length - 8]) return;
|
||||
const group = path[path.length - 7].id;
|
||||
const subgroup = path[path.length - 8].id;
|
||||
const land = pack.cells.h[i] >= 20;
|
||||
|
||||
|
||||
// specific elements
|
||||
if (group === "rivers") {tip("Click to edit the River"); return;}
|
||||
if (group === "routes") {tip("Click to edit the Route"); return;}
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ const optionsContent = document.getElementById("optionsContent");
|
|||
optionsContent.addEventListener("input", function(event) {
|
||||
const id = event.target.id, value = event.target.value;
|
||||
if (id === "mapWidthInput" || id === "mapHeightInput") mapSizeInputChange();
|
||||
else if (id === "densityInput" || id === "densityOutput") changeCellsDensity(value);
|
||||
else if (id === "densityInput" || id === "densityOutput") changeCellsDensity(+value);
|
||||
else if (id === "culturesInput") culturesOutput.value = value;
|
||||
else if (id === "culturesOutput") culturesInput.value = value;
|
||||
else if (id === "regionsInput" || id === "regionsOutput") changeStatesNumber(value);
|
||||
|
|
@ -598,8 +598,7 @@ optionsContent.addEventListener("input", function(event) {
|
|||
else if (id === "powerOutput") powerInput.value = value;
|
||||
else if (id === "neutralInput") neutralOutput.value = value;
|
||||
else if (id === "neutralOutput") neutralInput.value = value;
|
||||
else if (id === "manorsInput") manorsOutput.value = value;
|
||||
else if (id === "manorsOutput") manorsInput.value = value;
|
||||
else if (id === "manorsInput") changeBurgsNumberSlider(value);
|
||||
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value);
|
||||
else if (id === "tooltipSizeInput" || id === "tooltipSizeOutput") changeTooltipSize(value);
|
||||
else if (id === "transparencyInput") changeDialogsTransparency(value);
|
||||
|
|
@ -608,9 +607,10 @@ optionsContent.addEventListener("input", function(event) {
|
|||
});
|
||||
|
||||
optionsContent.addEventListener("change", function(event) {
|
||||
if (event.target.dataset.stored) lock(event.target.dataset.stored);
|
||||
if (event.target.dataset.stored) lock(event.target.dataset.stored);
|
||||
const id = event.target.id, value = event.target.value;
|
||||
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
|
||||
else if (id === "optionsSeed") generateMapWithSeed();
|
||||
});
|
||||
|
||||
optionsContent.addEventListener("click", function(event) {
|
||||
|
|
@ -625,7 +625,7 @@ function mapSizeInputChange() {
|
|||
changeMapSize();
|
||||
autoResize = false;
|
||||
localStorage.setItem("mapWidth", mapWidthInput.value);
|
||||
localStorage.setItem("mapHeight", mapHeightInput.value);
|
||||
localStorage.setItem("mapHeight", mapHeightInput.value);
|
||||
}
|
||||
|
||||
// change svg size on manual size change or window resize, do not change graph size
|
||||
|
|
@ -658,7 +658,7 @@ function toggleFullscreen() {
|
|||
mapWidthInput.value = graphWidth;
|
||||
mapHeightInput.value = graphHeight;
|
||||
}
|
||||
changeMapSize();
|
||||
changeMapSize();
|
||||
}
|
||||
|
||||
function generateMapWithSeed() {
|
||||
|
|
@ -703,10 +703,10 @@ function restoreDefaultZoomExtent() {
|
|||
}
|
||||
|
||||
function changeCellsDensity(value) {
|
||||
densityInput.value = densityOutput.value = value;
|
||||
if (value == 3) densityOutput.style.color = "red";
|
||||
else if (value == 2) densityOutput.style.color = "yellow";
|
||||
else if (value == 1) densityOutput.style.color = "green";
|
||||
densityOutput.value = value * 10 + "K";
|
||||
if (value > 5) densityOutput.style.color = "#b12117";
|
||||
else if (value > 1) densityOutput.style.color = "#dfdf12";
|
||||
else densityOutput.style.color = "#038603";
|
||||
}
|
||||
|
||||
function changeStatesNumber(value) {
|
||||
|
|
@ -715,6 +715,10 @@ function changeStatesNumber(value) {
|
|||
labels.select("#countries").attr("data-size", Math.max(rn(18 - value / 6), 4));
|
||||
}
|
||||
|
||||
function changeBurgsNumberSlider(value) {
|
||||
manorsOutput.value = value == 1000 ? "auto" : value;
|
||||
}
|
||||
|
||||
function changeUIsize(value) {
|
||||
uiSizeInput.value = uiSizeOutput.value = value;
|
||||
document.getElementsByTagName("body")[0].style.fontSize = value * 11 + "px";
|
||||
|
|
@ -785,7 +789,7 @@ function applyStoredOptions() {
|
|||
function randomizeOptions() {
|
||||
Math.seedrandom(seed); // reset seed to initial one
|
||||
if (!locked("regions")) regionsInput.value = regionsOutput.value = rand(12, 17);
|
||||
if (!locked("manors")) manorsInput.value = manorsOutput.value = rn(0.5 + Math.random(), 1);
|
||||
if (!locked("manors")) {manorsInput.value = 1000; manorsOutput.value = "auto";}
|
||||
if (!locked("power")) powerInput.value = powerOutput.value = rand(0, 4);
|
||||
if (!locked("neutral")) neutralInput.value = neutralOutput.value = rn(0.8 + Math.random(), 1);
|
||||
if (!locked("cultures")) culturesInput.value = culturesOutput.value = rand(10, 15);
|
||||
|
|
|
|||
|
|
@ -433,4 +433,20 @@ function getAbsolutePath(href) {
|
|||
var link = document.createElement("a");
|
||||
link.href = href;
|
||||
return link.href;
|
||||
}
|
||||
}
|
||||
|
||||
// from https://davidwalsh.name/javascript-debounce-function
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
var later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
}
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue