mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
v 0.9b
This commit is contained in:
parent
c22d0d755a
commit
436172ee2f
6 changed files with 420 additions and 129 deletions
31
index.css
31
index.css
|
|
@ -1502,33 +1502,38 @@ svg.button {
|
|||
width: 15em;
|
||||
}
|
||||
|
||||
#reliefEditor input[type="number"] {
|
||||
width: 3em;
|
||||
}
|
||||
|
||||
#reliefIconsDiv {
|
||||
margin-top: 2px;
|
||||
border: 1px solid #d4d4d4;
|
||||
padding: 2px;
|
||||
padding: 2px;
|
||||
max-width: 30vw;
|
||||
}
|
||||
|
||||
#reliefIconsDiv > button {
|
||||
#reliefIconsDiv > svg {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 15%;
|
||||
border: 1px solid #939393;
|
||||
background-color: #eef6fb;
|
||||
border: 1px solid #a9a9a9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#reliefIconsDiv > button:hover {
|
||||
#reliefIconsDiv > svg:hover {
|
||||
border-color: #5c5c5c;
|
||||
background-color: #eef6fb;
|
||||
}
|
||||
|
||||
#reliefIconsDiv > button.pressed {
|
||||
border: 1.5px outset #a6a6da;
|
||||
background-color: #ecd8d8;
|
||||
#reliefIconsDiv > svg.pressed {
|
||||
border: 1px solid #b3352c;
|
||||
background-color: #eef6fb;
|
||||
}
|
||||
|
||||
#reliefIconsSeletionAny {
|
||||
display: none;
|
||||
font-style: italic;
|
||||
width: 24px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: central;
|
||||
}
|
||||
|
||||
#alertMessage {
|
||||
|
|
|
|||
412
index.html
412
index.html
File diff suppressed because one or more lines are too long
28
main.js
28
main.js
|
|
@ -7,7 +7,7 @@
|
|||
// See also https://github.com/Azgaar/Fantasy-Map-Generator/issues/153
|
||||
|
||||
"use strict";
|
||||
const version = "0.80b"; // generator version
|
||||
const version = "0.9b"; // generator version
|
||||
document.title += " v " + version;
|
||||
|
||||
// append svg layers (in default order)
|
||||
|
|
@ -112,29 +112,22 @@ setTimeout(showWelcomeMessage, 8000);
|
|||
function showWelcomeMessage() {
|
||||
// Changelog dialog window
|
||||
if (localStorage.getItem("version") != version) {
|
||||
const link = 'https://www.reddit.com/r/FantasyMapGenerator/comments/bfskpi/update_stable_version_is_released_v_08b/?utm_source=share&utm_medium=web2x'; // announcement on Reddit
|
||||
const link = 'https://www.reddit.com/r/FantasyMapGenerator/comments/bynoz7/update_new_version_is_published_v_09b/'; // announcement on Reddit
|
||||
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version <b>${version}</b>.
|
||||
|
||||
This version is <b>not compatible</b> with older <i>.map</i> files.
|
||||
Please use an <a href='https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog' target='_blank'>archived version</a> to open the file.
|
||||
This version is compatible with v 0.8b, but not with older <i>.map</i> files.
|
||||
Please use an <a href='https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog' target='_blank'>archived version</a> to open old files.
|
||||
|
||||
<ul><a href=${link} target='_blank'>Main changes:</a>
|
||||
<li>World size and climate configuration</li>
|
||||
<li>Biomes layer and biomes editor</li>
|
||||
<li>Temperature and precipitation layers</li>
|
||||
<li>Reworked population model (now depends on biome)</li>
|
||||
<li>New states and cultures spread algorithm</li>
|
||||
<li>15 new cultures</li>
|
||||
<li>Texture layer and ability to link a custom texture</li>
|
||||
<li>Seed history (to open previously generated maps)</li>
|
||||
<li>Optimization (faster generation and smoother edit experience)</li>
|
||||
<li>UI and usability changes</li>
|
||||
<li>Reworked <a href='https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys' target='_blank'>hotkeys</a></li>
|
||||
<li>Relief icons by Arzak Rubin</li>
|
||||
<li>Ability to re-generate Burgs</li>
|
||||
<li>Ability to re-generate States</li>
|
||||
<li>Bug fixes</li>
|
||||
</ul>
|
||||
|
||||
<p>Join our <a href='https://www.reddit.com/r/FantasyMapGenerator' target='_blank'>Reddit community</a> and
|
||||
<a href='https://discordapp.com/invite/X7E84HU' target='_blank'>Discord server</a>
|
||||
to share created maps, discuss the Generator, report bugs, ask questions and propose new features.</p>
|
||||
to ask questions, share maps, discuss the Generator, report bugs and propose new features.</p>
|
||||
|
||||
<p>Thanks for all supporters on <a href='https://www.patreon.com/azgaar' target='_blank'>Patreon</a>!</i></p>`;
|
||||
|
||||
|
|
@ -233,7 +226,8 @@ function applyDefaultBiomesSystem() {
|
|||
const i = new Uint8Array(d3.range(0, name.length));
|
||||
const habitability = new Uint16Array([0,2,5,15,25,50,100,80,90,10,2,0]);
|
||||
const iconsDensity = new Uint8Array([0,3,2,120,120,120,120,150,150,100,5,0]);
|
||||
const icons = [{},{dune:1},{dune:1},{acacia:1, grass:9},{grass:1},{acacia:1, palm:1},{deciduous:1},{acacia:7, palm:2, deciduous:1},{deciduous:7, swamp:3},{conifer:1},{grass:1},{}];
|
||||
//const icons = [{},{dune:1},{dune:1},{acacia:1, grass:9},{grass:1},{acacia:1, palm:1},{deciduous:1},{acacia:7, palm:2, deciduous:1},{deciduous:7, swamp:3},{conifer:1},{grass:1},{}];
|
||||
const icons = [{},{dune:3, cactus:6, deadTree:1},{dune:9, deadTree:1},{acacia:1, grass:9},{grass:1},{acacia:8, palm:1},{deciduous:1},{acacia:5, palm:3, deciduous:1, swamp:2},{deciduous:5, swamp:3},{conifer:1},{grass:1},{}];
|
||||
const cost = new Uint8Array([10,200,150,60,50,70,70,80,90,80,100,255]); // biome movement cost
|
||||
const biomesMartix = [
|
||||
new Uint8Array([1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]),
|
||||
|
|
|
|||
|
|
@ -34,15 +34,15 @@
|
|||
for (const [cx, cy] of poissonDiscSampler(e[0], e[1], e[2], e[3], radius)) {
|
||||
if (!d3.polygonContains(polygon, [cx, cy])) continue;
|
||||
let h = rn((4 + Math.random()) * size, 2);
|
||||
const icon = getBiomeIcon(biomesData.icons[b]);
|
||||
const icon = getBiomeIcon(i, biomesData.icons[b]);
|
||||
if (icon === "#relief-grass-1") h *= 1.3;
|
||||
relief.push({t: icon, c: i, x: rn(cx-h, 2), y: rn(cy-h, 2), s: h*2});
|
||||
}
|
||||
}
|
||||
|
||||
function placeReliefIcons() {
|
||||
function placeReliefIcons(i) {
|
||||
const radius = 2 / density;
|
||||
const [icon, h] = getReliefIcon(height);
|
||||
const [icon, h] = getReliefIcon(i, height);
|
||||
|
||||
for (const [cx, cy] of poissonDiscSampler(e[0], e[1], e[2], e[3], radius)) {
|
||||
if (!d3.polygonContains(polygon, [cx, cy])) continue;
|
||||
|
|
@ -50,10 +50,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
function getReliefIcon(h) {
|
||||
const type = h > 70 ? "mount" : "hill";
|
||||
function getReliefIcon(i, h) {
|
||||
const temp = grid.cells.temp[pack.cells.g[i]];
|
||||
const type = h > 70 && temp < 0 ? "mountSnow" : h > 70 ? "mount" : "hill";
|
||||
const size = h > 70 ? (h - 45) * mod : Math.min(Math.max((h - 40) * mod, 3), 6);
|
||||
return ["#relief-" + type + "-1", size];
|
||||
return ["#relief-" + type + "-" + getIcon(type), size];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -71,8 +72,25 @@
|
|||
console.timeEnd('drawRelief');
|
||||
}
|
||||
|
||||
function getBiomeIcon(i) {
|
||||
return "#relief-" + i[Math.floor(Math.random() * i.length)] + "-1";
|
||||
function getBiomeIcon(i, b) {
|
||||
let type = b[Math.floor(Math.random() * b.length)];
|
||||
const temp = grid.cells.temp[pack.cells.g[i]];
|
||||
if (type === "conifer" && temp < 0) type = "coniferSnow";
|
||||
return "#relief-" + type + "-" + getIcon(type);
|
||||
}
|
||||
|
||||
function getIcon(type) {
|
||||
switch (type) {
|
||||
case "mount": return rand(2,7);
|
||||
case "mountSnow": return rand(1,6);
|
||||
case "hill": return rand(2,5);
|
||||
case "conifer": return 2;
|
||||
case "coniferSnow": return 1;
|
||||
case "swamp": return rand(2,3);
|
||||
case "cactus": return rand(1,3);
|
||||
case "deadTree": return rand(1,2);
|
||||
default: return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ReliefIcons;
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@ function uploadFile(file, callback) {
|
|||
|
||||
function parseLoadedData(data) {
|
||||
closeDialogs();
|
||||
const reliefIcons = document.getElementById("defs-relief").innerHTML; // save relief icons
|
||||
|
||||
void function parseParameters() {
|
||||
const params = data[0].split("|");
|
||||
|
|
@ -385,8 +386,14 @@ function parseLoadedData(data) {
|
|||
}()
|
||||
|
||||
void function resolveVersionConflicts() {
|
||||
document.getElementById("regions").removeAttribute("opacity"); // 0.8.28b changed opacity slider from regions to statesBody
|
||||
}
|
||||
if (parseFloat(data[0].split("|")[0]) == 0.8) {
|
||||
// 0.9 has additional relief icons to be included into older maps
|
||||
document.getElementById("defs-relief").innerHTML = reliefIcons;
|
||||
|
||||
// 0.8.28b changed opacity slider from regions to statesBody
|
||||
document.getElementById("regions").removeAttribute("opacity");
|
||||
}
|
||||
}()
|
||||
|
||||
changeMapSize();
|
||||
restoreDefaultEvents();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ function editReliefIcon() {
|
|||
if (!layerIsOn("toggleRelief")) toggleRelief();
|
||||
|
||||
terrain.selectAll("use").call(d3.drag().on("drag", dragReliefIcon)).classed("draggable", true);
|
||||
elSelected = d3.select(d3.event.target);
|
||||
elSelected = d3.select(d3.event.target);
|
||||
|
||||
restoreEditMode();
|
||||
updateReliefIconSelected();
|
||||
|
|
@ -27,7 +27,7 @@ function editReliefIcon() {
|
|||
|
||||
document.getElementById("reliefSize").addEventListener("input", changeIconSize);
|
||||
document.getElementById("reliefSizeNumber").addEventListener("input", changeIconSize);
|
||||
reliefIconsDiv.querySelectorAll("button").forEach(el => el.addEventListener("click", changeIcon));
|
||||
reliefIconsDiv.querySelectorAll("svg").forEach(el => el.addEventListener("click", changeIcon));
|
||||
|
||||
document.getElementById("reliefCopy").addEventListener("click", copyIcon);
|
||||
document.getElementById("reliefMoveFront").addEventListener("click", () => elSelected.raise());
|
||||
|
|
@ -53,8 +53,8 @@ function editReliefIcon() {
|
|||
|
||||
function updateReliefIconSelected() {
|
||||
const type = elSelected.attr("data-type");
|
||||
reliefIconsDiv.querySelectorAll("button.pressed").forEach(b => b.classList.remove("pressed"));
|
||||
reliefIconsDiv.querySelector("button[data-type='"+type+"']").classList.add("pressed");
|
||||
reliefIconsDiv.querySelectorAll("svg.pressed").forEach(b => b.classList.remove("pressed"));
|
||||
reliefIconsDiv.querySelector("svg[data-type='"+type+"']").classList.add("pressed");
|
||||
}
|
||||
|
||||
function updateReliefSizeInput() {
|
||||
|
|
@ -85,10 +85,10 @@ function editReliefIcon() {
|
|||
reliefSpacingDiv.style.display = "block";
|
||||
reliefIconsSeletionAny.style.display = "none";
|
||||
|
||||
const pressedType = reliefIconsDiv.querySelector("button.pressed");
|
||||
const pressedType = reliefIconsDiv.querySelector("svg.pressed");
|
||||
if (pressedType.id === "reliefIconsSeletionAny") { // in "any" is pressed, select first type
|
||||
reliefIconsSeletionAny.classList.remove("pressed");
|
||||
reliefIconsDiv.querySelector("button").classList.add("pressed");
|
||||
reliefIconsSeletionAny.classList.remove("pressed");
|
||||
reliefIconsDiv.querySelector("svg").classList.add("pressed");
|
||||
}
|
||||
|
||||
viewbox.style("cursor", "crosshair").call(d3.drag().on("start", dragToAdd)).on("touchmove mousemove", moveBrush);
|
||||
|
|
@ -98,18 +98,18 @@ function editReliefIcon() {
|
|||
function moveBrush() {
|
||||
showMainTip();
|
||||
const point = d3.mouse(this);
|
||||
const radius = +reliefRadius.value;
|
||||
const radius = +reliefRadiusNumber.value;
|
||||
moveCircle(point[0], point[1], radius);
|
||||
}
|
||||
|
||||
function dragToAdd() {
|
||||
const pressed = reliefIconsDiv.querySelector("button.pressed");
|
||||
const pressed = reliefIconsDiv.querySelector("svg.pressed");
|
||||
if (!pressed) {tip("Please select an icon", false, error); return;}
|
||||
|
||||
const type = pressed.dataset.type;
|
||||
const r = +reliefRadius.value;
|
||||
const spacing = +reliefSpacing.value;
|
||||
const size = +reliefSize.value;
|
||||
const r = +reliefRadiusNumber.value;
|
||||
const spacing = +reliefSpacingNumber.value;
|
||||
const size = +reliefSizeNumber.value;
|
||||
|
||||
// build a quadtree
|
||||
const tree = d3.quadtree();
|
||||
|
|
@ -166,10 +166,10 @@ function editReliefIcon() {
|
|||
}
|
||||
|
||||
function dragToRemove() {
|
||||
const pressed = reliefIconsDiv.querySelector("button.pressed");
|
||||
const pressed = reliefIconsDiv.querySelector("svg.pressed");
|
||||
if (!pressed) {tip("Please select an icon", false, error); return;}
|
||||
|
||||
const r = +reliefRadius.value;
|
||||
const r = +reliefRadiusNumber.value;
|
||||
const type = pressed.dataset.type;
|
||||
const icons = type ? terrain.selectAll("use[data-type='"+type+"']") : terrain.selectAll("use");
|
||||
const tree = d3.quadtree();
|
||||
|
|
@ -187,8 +187,7 @@ function editReliefIcon() {
|
|||
}
|
||||
|
||||
function changeIconSize() {
|
||||
const size = +reliefSize.value;
|
||||
reliefSize.value = reliefSizeNumber.value = size;
|
||||
const size = +reliefSizeNumber.value;
|
||||
if (!reliefIndividual.classList.contains("pressed")) return;
|
||||
|
||||
const shift = (size - +elSelected.attr("width")) / 2;
|
||||
|
|
@ -200,7 +199,7 @@ function editReliefIcon() {
|
|||
function changeIcon() {
|
||||
if (this.classList.contains("pressed")) return;
|
||||
|
||||
reliefIconsDiv.querySelectorAll("button.pressed").forEach(b => b.classList.remove("pressed"))
|
||||
reliefIconsDiv.querySelectorAll("svg.pressed").forEach(b => b.classList.remove("pressed"))
|
||||
this.classList.add("pressed");
|
||||
|
||||
if (reliefIndividual.classList.contains("pressed")) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue