latest version

This commit is contained in:
howlingsails 2022-08-16 18:26:34 -07:00
parent 41432ac944
commit c477c8dfcd
36 changed files with 3979 additions and 832 deletions

BIN
_maps/.DS_Store vendored Normal file

Binary file not shown.

BIN
_maps/working/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
[{"name":"Wildlands","i":0,"base":1,"origin":null,"shield":"round"},{"name":"Dhommeam (Dwarf)","base":35,"shield":"erebor","center":2793,"i":1,"color":"#ffed6f","type":"Highland","expansionism":0.5,"origin":0,"code":"DD"},{"name":"Dunirr (Dwarf)","base":35,"shield":"ironHills","center":5754,"i":2,"color":"#dababf","type":"Generic","expansionism":0.1,"origin":0,"code":"DU"},{"name":"Mudtoe (Dwarf)","base":35,"shield":"erebor","center":183,"i":3,"color":"#ee4395","type":"Highland","expansionism":0.4,"origin":0,"code":"MD"},{"name":"Khazadur (Dwarf)","base":35,"shield":"erebor","center":3542,"i":4,"color":"#eb8de7","type":"Highland","expansionism":0.5,"origin":0,"code":"KD"},{"name":"Yotunn (Giant)","base":38,"shield":"pavise","center":702,"i":5,"color":"#80b1d3","type":"Hunting","expansionism":0.6,"origin":0,"code":"YG"},{"name":"Shazgob (Orc)","base":37,"shield":"moriaOrc","center":5639,"i":6,"color":"#fccde5","type":"Hunting","expansionism":0.7,"origin":0,"code":"SO"},{"name":"Gul (Orc)","base":37,"shield":"moriaOrc","center":6040,"i":7,"color":"#2f96e0","type":"Highland","expansionism":0.5,"origin":0,"code":"GO"},{"name":"Gongrem (Dwarf)","base":35,"shield":"erebor","center":2190,"i":8,"color":"#b3de69","type":"Highland","expansionism":0.3,"origin":0,"code":"GD"},{"name":"Gralcek (Human)","base":16,"shield":"round","center":3704,"i":9,"color":"#bc80bd","type":"Generic","expansionism":0.1,"origin":0,"code":"GH"},{"name":"Fruthos (Human)","base":32,"shield":"fantasy5","center":6517,"i":10,"color":"#ccebc5","type":"River","expansionism":0.4,"origin":0,"code":"FH"},{"name":"Rulor (Human)","base":32,"shield":"roman","center":2763,"i":11,"color":"#ff8c38","type":"Lake","expansionism":0.4,"origin":0,"code":"RH"},{"name":"Mazoga (Orc)","base":37,"shield":"moriaOrc","center":5278,"i":12,"color":"#6e40aa","type":"Highland","expansionism":0.5,"origin":0,"code":"MO"},{"name":"Heenzurm (Goblin)","base":36,"shield":"moriaOrc","center":3211,"i":13,"color":"#28ea8d","type":"Hunting","expansionism":0.9,"origin":0,"code":"HG"},{"name":"Zildud (Orc)","base":37,"shield":"moriaOrc","center":249,"i":14,"color":"#aff05b","type":"Highland","expansionism":0.5,"origin":0,"code":"ZO"},{"name":"Ginikirr (Dwarf)","base":35,"shield":"erebor","center":2794,"i":15,"color":"#8dd3c7","type":"Highland","expansionism":0.4,"origin":0,"code":"GI"},{"name":"Lothian (Elf)","base":33,"shield":"wedged","center":3477,"i":16,"color":"#c6b9c1","type":"River","expansionism":0.4,"origin":0,"code":"LE"},{"name":"Zakaos (Giant)","base":38,"shield":"pavise","center":439,"i":17,"color":"#fdb462","type":"Generic","expansionism":0.1,"origin":0,"code":"ZG"},{"name":"Lagakh (Orc)","base":37,"shield":"urukHai","center":2558,"i":18,"color":"#fb8072","type":"Highland","expansionism":0.5,"origin":0,"code":"LO"}]

View file

@ -0,0 +1 @@
[{"name":"Wildlands","i":0,"base":1,"origin":null,"shield":"round"},{"name":"Dhommeam (Dwarf)","base":35,"shield":"erebor","center":2793,"i":1,"color":"#ffed6f","type":"Highland","expansionism":0.5,"origin":0,"code":"DD"},{"name":"Dunirr (Dwarf)","base":35,"shield":"ironHills","center":5759,"i":2,"color":"#dababf","type":"Generic","expansionism":0.1,"origin":0,"code":"DU"},{"name":"Mudtoe (Dwarf)","base":35,"shield":"erebor","center":603,"i":3,"color":"#ee4395","type":"Highland","expansionism":0.4,"origin":0,"code":"MD"},{"name":"Khazadur (Dwarf)","base":35,"shield":"erebor","center":2608,"i":4,"color":"#eb8de7","type":"Nomadic","expansionism":1.4,"origin":0,"code":"KD"},{"name":"Yotunn (Giant)","base":38,"shield":"pavise","center":701,"i":5,"color":"#80b1d3","type":"River","expansionism":0.3,"origin":0,"code":"YG"},{"name":"Shazgob (Orc)","base":37,"shield":"moriaOrc","center":5644,"i":6,"color":"#fccde5","type":"Hunting","expansionism":0.7,"origin":0,"code":"SO"},{"name":"Gul (Orc)","base":37,"shield":"moriaOrc","center":6045,"i":7,"color":"#2f96e0","type":"Highland","expansionism":0.5,"origin":0,"code":"GO"},{"name":"Gongrem (Dwarf)","base":35,"shield":"erebor","center":2190,"i":8,"color":"#b3de69","type":"Highland","expansionism":0.3,"origin":0,"code":"GD"},{"name":"Gralcek (Human)","base":16,"shield":"round","center":3922,"i":9,"color":"#bc80bd","type":"Hunting","expansionism":0.8,"origin":0,"code":"GH"},{"name":"Fruthos (Human)","base":32,"shield":"fantasy5","center":6399,"i":10,"color":"#ccebc5","type":"Naval","expansionism":0.6,"origin":0,"code":"FH"},{"name":"Rulor (Human)","base":32,"shield":"roman","center":2632,"i":11,"color":"#ff8c38","type":"Nomadic","expansionism":0.9,"origin":0,"code":"RH"},{"name":"Mazoga (Orc)","base":37,"shield":"moriaOrc","center":4222,"i":12,"color":"#6e40aa","type":"Hunting","expansionism":0.9,"origin":0,"code":"MO"},{"name":"Heenzurm (Goblin)","base":36,"shield":"moriaOrc","center":3211,"i":13,"color":"#28ea8d","type":"Hunting","expansionism":0.9,"origin":0,"code":"HG"},{"name":"Zildud (Orc)","base":37,"shield":"moriaOrc","center":5769,"i":14,"color":"#aff05b","type":"Highland","expansionism":0.5,"origin":0,"code":"ZO"},{"name":"Ginikirr (Dwarf)","base":35,"shield":"erebor","center":2794,"i":15,"color":"#8dd3c7","type":"Highland","expansionism":0.4,"origin":0,"code":"GI"},{"name":"Lothian (Elf)","base":33,"shield":"wedged","center":3480,"i":16,"color":"#c6b9c1","type":"River","expansionism":0.4,"origin":0,"code":"LE"},{"name":"Zakaos (Giant)","base":38,"shield":"pavise","center":417,"i":17,"color":"#fdb462","type":"Nomadic","expansionism":1.2,"origin":0,"code":"ZG"},{"name":"Lagakh (Orc)","base":37,"shield":"urukHai","center":2558,"i":18,"color":"#fb8072","type":"Highland","expansionism":0.5,"origin":0,"code":"LO"}]

View file

@ -0,0 +1 @@
[{"name":"Wildlands","i":0,"base":1,"origin":null,"shield":"round"},{"name":"Dhommeam (Dwarf)","base":35,"shield":"erebor","center":2793,"i":1,"color":"#ffed6f","type":"Highland","expansionism":0.5,"origin":0,"code":"DD"},{"name":"Dunirr (Dwarf)","base":35,"shield":"ironHills","center":5754,"i":2,"color":"#dababf","type":"Generic","expansionism":0.1,"origin":0,"code":"DU"},{"name":"Mudtoe (Dwarf)","base":35,"shield":"erebor","center":183,"i":3,"color":"#ee4395","type":"Highland","expansionism":0.4,"origin":0,"code":"MD"},{"name":"Khazadur (Dwarf)","base":35,"shield":"erebor","center":3542,"i":4,"color":"#eb8de7","type":"Highland","expansionism":0.5,"origin":0,"code":"KD"},{"name":"Yotunn (Giant)","base":38,"shield":"pavise","center":702,"i":5,"color":"#80b1d3","type":"Hunting","expansionism":0.6,"origin":0,"code":"YG"},{"name":"Shazgob (Orc)","base":37,"shield":"moriaOrc","center":5639,"i":6,"color":"#fccde5","type":"Hunting","expansionism":0.7,"origin":0,"code":"SO"},{"name":"Gul (Orc)","base":37,"shield":"moriaOrc","center":6040,"i":7,"color":"#2f96e0","type":"Highland","expansionism":0.5,"origin":0,"code":"GO"},{"name":"Gongrem (Dwarf)","base":35,"shield":"erebor","center":2190,"i":8,"color":"#b3de69","type":"Highland","expansionism":0.3,"origin":0,"code":"GD"},{"name":"Gralcek (Human)","base":16,"shield":"round","center":3704,"i":9,"color":"#bc80bd","type":"Generic","expansionism":0.1,"origin":0,"code":"GH"},{"name":"Fruthos (Human)","base":32,"shield":"fantasy5","center":6517,"i":10,"color":"#ccebc5","type":"River","expansionism":0.4,"origin":0,"code":"FH"},{"name":"Rulor (Human)","base":32,"shield":"roman","center":2763,"i":11,"color":"#ff8c38","type":"Lake","expansionism":0.4,"origin":0,"code":"RH"},{"name":"Mazoga (Orc)","base":37,"shield":"moriaOrc","center":5278,"i":12,"color":"#6e40aa","type":"Highland","expansionism":0.5,"origin":0,"code":"MO"},{"name":"Heenzurm (Goblin)","base":36,"shield":"moriaOrc","center":3211,"i":13,"color":"#28ea8d","type":"Hunting","expansionism":0.9,"origin":0,"code":"HG"},{"name":"Zildud (Orc)","base":37,"shield":"moriaOrc","center":249,"i":14,"color":"#aff05b","type":"Highland","expansionism":0.5,"origin":0,"code":"ZO"},{"name":"Ginikirr (Dwarf)","base":35,"shield":"erebor","center":2794,"i":15,"color":"#8dd3c7","type":"Highland","expansionism":0.4,"origin":0,"code":"GI"},{"name":"Lothian (Elf)","base":33,"shield":"wedged","center":3477,"i":16,"color":"#c6b9c1","type":"River","expansionism":0.4,"origin":0,"code":"LE"},{"name":"Zakaos (Giant)","base":38,"shield":"pavise","center":439,"i":17,"color":"#fdb462","type":"Generic","expansionism":0.1,"origin":0,"code":"ZG"},{"name":"Lagakh (Orc)","base":37,"shield":"urukHai","center":2558,"i":18,"color":"#fb8072","type":"Highland","expansionism":0.5,"origin":0,"code":"LO"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
undefined

View file

@ -0,0 +1 @@
undefined

View file

@ -0,0 +1 @@
undefined

View file

@ -0,0 +1 @@
530

View file

@ -0,0 +1 @@
530

View file

@ -0,0 +1 @@
530

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -85,7 +85,7 @@ a {
}
#prec text {
font-size: 32px;
font-size: 24px;
stroke: none;
text-shadow: 1px 1px 1px #9daac9;
user-select: none;
@ -297,12 +297,17 @@ i.icon-lock {
}
}
#provinceLabels,
#burgLabels {
dominant-baseline: alphabetic;
text-anchor: middle;
font-size: 0.1em;
}
#provinceLabels {
dominant-baseline: alphabetic;
text-anchor: leftOver;
font-size: 0.2em;
text-shadow: 1px 1px #e7ffa1;
}
#routeLength,
#coastlineArea {
background-color: #eeeeee;

View file

@ -1046,7 +1046,7 @@
<option value="english" data-max="10">English</option>
<option value="antique" data-max="10">Antique</option>
<option value="highFantasy" data-max="17">High Fantasy</option>
<option value="darkFantasy" data-max="18">Dark Fantasy</option>
<option value="darkFantasy" data-max="32">Dark Fantasy</option>
<option value="random" data-max="100">Random</option>
</select>
</td>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,19 @@ function getMapData() {
TIME && console.time("createMapData");
const date = new Date();
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
const params = [version, license, dateString, seed, graphWidth, graphHeight, mapId].join("|");
const dateString =
date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
const license =
"File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
const params = [
version,
license,
dateString,
seed,
graphWidth,
graphHeight,
mapId,
].join("|");
const settings = [
distanceUnitInput.value,
distanceScaleInput.value,
@ -34,10 +44,14 @@ function getMapData() {
+hideLabels.checked,
stylePreset.value,
+rescaleLabels.checked,
urbanDensity
urbanDensity,
].join("|");
const coords = JSON.stringify(mapCoordinates);
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
const biomes = [
biomesData.color,
biomesData.habitability,
biomesData.name,
].join("|");
const notesData = JSON.stringify(notes);
const rulersString = rulers.toString();
const fonts = JSON.stringify(getUsedFonts(svg.node()));
@ -54,8 +68,15 @@ function getMapData() {
const serializedSVG = new XMLSerializer().serializeToString(cloneEl);
const {spacing, cellsX, cellsY, boundary, points, features} = grid;
const gridGeneral = JSON.stringify({spacing, cellsX, cellsY, boundary, points, features});
const { spacing, cellsX, cellsY, boundary, points, features } = grid;
const gridGeneral = JSON.stringify({
spacing,
cellsX,
cellsY,
boundary,
points,
features,
});
const packFeatures = JSON.stringify(pack.features);
const cultures = JSON.stringify(pack.cultures);
const states = JSON.stringify(pack.states);
@ -75,7 +96,7 @@ function getMapData() {
.join("/");
// round population to save space
const pop = Array.from(pack.cells.pop).map(p => rn(p, 4));
const pop = Array.from(pack.cells.pop).map((p) => rn(p, 4));
// data format as below
const mapData = [
@ -114,7 +135,7 @@ function getMapData() {
rivers,
rulersString,
fonts,
markers
markers,
].join("\r\n");
TIME && console.timeEnd("createMapData");
@ -122,23 +143,112 @@ function getMapData() {
}
// Download .map file
function dowloadMap() {
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
closeDialogs("#alert");
function downloadMapOrig() {
const mapData = getMapData();
const blob = new Blob([mapData], {type: "text/plain"});
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + ".map";
link.href = URL;
link.click();
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
}
function downloadMarkers() {
const mapData = JSON.stringify(pack.markers);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-markers.json";
link.href = URL;
link.click();
}
function downloadBurgs() {
const mapData = JSON.stringify(pack.burgs);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-burgs.json";
link.href = URL;
link.click();
}
function downloadReligions() {
const mapData = JSON.stringify(pack.religions);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-religions.json";
link.href = URL;
link.click();
}
function downloadCultures() {
const mapData = JSON.stringify(pack.cultures);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-cultures.json";
link.href = URL;
link.click();
}
function downloadStates() {
const mapData = JSON.stringify(pack.states);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-states.json";
link.href = URL;
link.click();
}
function downloadNotes() {
const mapData = JSON.stringify(pack.notes);
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-notes.json";
link.href = URL;
link.click();
}
function downloadPopRates() {
const mapData = populationRate * urbanization;
const blob = new Blob([mapData], { type: "text/plain" });
const URL = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = getFileName() + "-poprate.txt";
link.href = URL;
link.click();
}
function dowloadMap() {
if (customization)
return tip(
"Map cannot be saved when edit mode is active, please exit the mode and retry",
false,
"error"
);
closeDialogs("#alert");
downloadMapOrig();
downloadMarkers();
downloadBurgs();
downloadCultures();
downloadNotes();
downloadReligions();
downloadPopRates();
downloadStates();
window.URL.revokeObjectURL(URL);
}
async function saveToDropbox() {
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
if (customization)
return tip(
"Map cannot be saved when edit mode is active, please exit the mode and retry",
false,
"error"
);
closeDialogs("#alert");
const mapData = getMapData();
const filename = getFileName() + ".map";
@ -152,12 +262,22 @@ async function saveToDropbox() {
}
function quickSave() {
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
if (customization)
return tip(
"Map cannot be saved when edit mode is active, please exit the mode and retry",
false,
"error"
);
const mapData = getMapData();
const blob = new Blob([mapData], {type: "text/plain"});
const blob = new Blob([mapData], { type: "text/plain" });
if (blob) ldb.set("lastMap", blob); // auto-save map
tip("Map is saved to browser memory. Please also save as .map file to secure progress", true, "success", 2000);
tip(
"Map is saved to browser memory. Please also save as .map file to secure progress",
true,
"success",
2000
);
}
const saveReminder = function () {
@ -170,7 +290,7 @@ const saveReminder = function () {
"Don't forget to save your map on a regular basis!",
"Just a gentle reminder for you to save the map",
"Please don't forget to save your progress (saving as .map is the best option)",
"Don't want to be reminded about need to save? Press CTRL+Q"
"Don't want to be reminded about need to save? Press CTRL+Q",
];
const interval = 15 * 60 * 1000; // remind every 15 minutes
@ -184,12 +304,22 @@ saveReminder();
function toggleSaveReminder() {
if (saveReminder.status) {
tip("Save reminder is turned off. Press CTRL+Q again to re-initiate", true, "warn", 2000);
tip(
"Save reminder is turned off. Press CTRL+Q again to re-initiate",
true,
"warn",
2000
);
clearInterval(saveReminder.reminder);
localStorage.setItem("noReminder", true);
saveReminder.status = 0;
} else {
tip("Save reminder is turned on. Press CTRL+Q to turn off", true, "warn", 2000);
tip(
"Save reminder is turned on. Press CTRL+Q to turn off",
true,
"warn",
2000
);
localStorage.removeItem("noReminder");
saveReminder();
}

View file

@ -7,89 +7,170 @@ function editBurg(id) {
const burg = id || d3.event.target.dataset.id;
elSelected = burgLabels.select("[data-id='" + burg + "']");
burgLabels.selectAll("text").call(d3.drag().on("start", dragBurgLabel)).classed("draggable", true);
burgLabels
.selectAll("text")
.call(d3.drag().on("start", dragBurgLabel))
.classed("draggable", true);
updateBurgValues();
$("#burgEditor").dialog({
title: "Edit Burg",
resizable: false,
close: closeBurgEditor,
position: {my: "left top", at: "left+10 top+10", of: "svg", collision: "fit"}
position: {
my: "left top",
at: "left+10 top+10",
of: "svg",
collision: "fit",
},
});
if (modules.editBurg) return;
modules.editBurg = true;
// add listeners
document.getElementById("burgGroupShow").addEventListener("click", showGroupSection);
document.getElementById("burgGroupHide").addEventListener("click", hideGroupSection);
document.getElementById("burgSelectGroup").addEventListener("change", changeGroup);
document.getElementById("burgInputGroup").addEventListener("change", createNewGroup);
document.getElementById("burgAddGroup").addEventListener("click", toggleNewGroupInput);
document.getElementById("burgRemoveGroup").addEventListener("click", removeBurgsGroup);
document
.getElementById("burgGroupShow")
.addEventListener("click", showGroupSection);
document
.getElementById("burgGroupHide")
.addEventListener("click", hideGroupSection);
document
.getElementById("burgSelectGroup")
.addEventListener("change", changeGroup);
document
.getElementById("burgInputGroup")
.addEventListener("change", createNewGroup);
document
.getElementById("burgAddGroup")
.addEventListener("click", toggleNewGroupInput);
document
.getElementById("burgRemoveGroup")
.addEventListener("click", removeBurgsGroup);
document.getElementById("burgName").addEventListener("input", changeName);
document.getElementById("burgNameReRandom").addEventListener("click", generateNameRandom);
document
.getElementById("burgNameReRandom")
.addEventListener("click", generateNameRandom);
document.getElementById("burgType").addEventListener("input", changeType);
document.getElementById("burgCulture").addEventListener("input", changeCulture);
document.getElementById("burgNameReCulture").addEventListener("click", generateNameCulture);
document.getElementById("burgPopulation").addEventListener("change", changePopulation);
burgBody.querySelectorAll(".burgFeature").forEach(el => el.addEventListener("click", toggleFeature));
document.getElementById("mfcgBurgSeed").addEventListener("change", changeSeed);
document.getElementById("regenerateMFCGBurgSeed").addEventListener("click", randomizeSeed);
document
.getElementById("burgCulture")
.addEventListener("input", changeCulture);
document
.getElementById("burgNameReCulture")
.addEventListener("click", generateNameCulture);
document
.getElementById("burgPopulation")
.addEventListener("change", changePopulation);
burgBody
.querySelectorAll(".burgFeature")
.forEach((el) => el.addEventListener("click", toggleFeature));
document
.getElementById("mfcgBurgSeed")
.addEventListener("change", changeSeed);
document
.getElementById("regenerateMFCGBurgSeed")
.addEventListener("click", randomizeSeed);
document.getElementById("burgStyleShow").addEventListener("click", showStyleSection);
document.getElementById("burgStyleHide").addEventListener("click", hideStyleSection);
document.getElementById("burgEditLabelStyle").addEventListener("click", editGroupLabelStyle);
document.getElementById("burgEditIconStyle").addEventListener("click", editGroupIconStyle);
document.getElementById("burgEditAnchorStyle").addEventListener("click", editGroupAnchorStyle);
document
.getElementById("burgStyleShow")
.addEventListener("click", showStyleSection);
document
.getElementById("burgStyleHide")
.addEventListener("click", hideStyleSection);
document
.getElementById("burgEditLabelStyle")
.addEventListener("click", editGroupLabelStyle);
document
.getElementById("burgEditIconStyle")
.addEventListener("click", editGroupIconStyle);
document
.getElementById("burgEditAnchorStyle")
.addEventListener("click", editGroupAnchorStyle);
document.getElementById("burgEmblem").addEventListener("click", openEmblemEdit);
document.getElementById("burgToggleMFCGMap").addEventListener("click", toggleMFCGMap);
document.getElementById("burgEditEmblem").addEventListener("click", openEmblemEdit);
document.getElementById("burgRelocate").addEventListener("click", toggleRelocateBurg);
document.getElementById("burglLegend").addEventListener("click", editBurgLegend);
document.getElementById("burgLock").addEventListener("click", toggleBurgLockButton);
document.getElementById("burgRemove").addEventListener("click", removeSelectedBurg);
document
.getElementById("burgEmblem")
.addEventListener("click", openEmblemEdit);
document
.getElementById("burgToggleMFCGMap")
.addEventListener("click", toggleMFCGMap);
document
.getElementById("burgEditEmblem")
.addEventListener("click", openEmblemEdit);
document
.getElementById("burgRelocate")
.addEventListener("click", toggleRelocateBurg);
document
.getElementById("burglLegend")
.addEventListener("click", editBurgLegend);
document
.getElementById("burgLock")
.addEventListener("click", toggleBurgLockButton);
document
.getElementById("burgRemove")
.addEventListener("click", removeSelectedBurg);
function updateBurgValues() {
const id = +elSelected.attr("data-id");
const b = pack.burgs[id];
const province = pack.cells.province[b.cell];
const provinceName = province ? pack.provinces[province].fullName + ", " : "";
const stateName = pack.states[b.state].fullName || pack.states[b.state].name;
document.getElementById("burgProvinceAndState").innerHTML = provinceName + stateName;
const provinceName = province
? pack.provinces[province].fullName + ", "
: "";
const stateName =
pack.states[b.state].fullName || pack.states[b.state].name;
document.getElementById("burgProvinceAndState").innerHTML =
provinceName + stateName;
document.getElementById("burgName").value = b.name;
document.getElementById("burgType").value = b.type || "Generic";
document.getElementById("burgPopulation").value = rn(b.population * populationRate * urbanization);
document.getElementById("burgEditAnchorStyle").style.display = +b.port ? "inline-block" : "none";
document.getElementById("burgPopulation").value = rn(
b.population * populationRate * urbanization
);
document.getElementById("burgEditAnchorStyle").style.display = +b.port
? "inline-block"
: "none";
// update list and select culture
const cultureSelect = document.getElementById("burgCulture");
cultureSelect.options.length = 0;
const cultures = pack.cultures.filter(c => !c.removed);
cultures.forEach(c => cultureSelect.options.add(new Option(c.name, c.i, false, c.i === b.culture)));
const cultures = pack.cultures.filter((c) => !c.removed);
cultures.forEach((c) =>
cultureSelect.options.add(
new Option(c.name, c.i, false, c.i === b.culture)
)
);
const temperature = grid.cells.temp[pack.cells.g[b.cell]];
document.getElementById("burgTemperature").innerHTML = convertTemperature(temperature);
document.getElementById("burgTemperatureLikeIn").innerHTML = getTemperatureLikeness(temperature);
document.getElementById("burgElevation").innerHTML = getHeight(pack.cells.h[b.cell]);
document.getElementById("burgTemperature").innerHTML =
convertTemperature(temperature);
document.getElementById("burgTemperatureLikeIn").innerHTML =
getTemperatureLikeness(temperature);
document.getElementById("burgElevation").innerHTML = getHeight(
pack.cells.h[b.cell]
);
// toggle features
if (b.capital) document.getElementById("burgCapital").classList.remove("inactive");
if (b.capital)
document.getElementById("burgCapital").classList.remove("inactive");
else document.getElementById("burgCapital").classList.add("inactive");
if (b.port) document.getElementById("burgPort").classList.remove("inactive");
if (b.port)
document.getElementById("burgPort").classList.remove("inactive");
else document.getElementById("burgPort").classList.add("inactive");
if (b.citadel) document.getElementById("burgCitadel").classList.remove("inactive");
if (b.citadel)
document.getElementById("burgCitadel").classList.remove("inactive");
else document.getElementById("burgCitadel").classList.add("inactive");
if (b.walls) document.getElementById("burgWalls").classList.remove("inactive");
if (b.walls)
document.getElementById("burgWalls").classList.remove("inactive");
else document.getElementById("burgWalls").classList.add("inactive");
if (b.plaza) document.getElementById("burgPlaza").classList.remove("inactive");
if (b.plaza)
document.getElementById("burgPlaza").classList.remove("inactive");
else document.getElementById("burgPlaza").classList.add("inactive");
if (b.temple) document.getElementById("burgTemple").classList.remove("inactive");
if (b.temple)
document.getElementById("burgTemple").classList.remove("inactive");
else document.getElementById("burgTemple").classList.add("inactive");
if (b.shanty) document.getElementById("burgShanty").classList.remove("inactive");
if (b.shanty)
document.getElementById("burgShanty").classList.remove("inactive");
else document.getElementById("burgShanty").classList.add("inactive");
//toggle lock
@ -101,7 +182,9 @@ function editBurg(id) {
select.options.length = 0; // remove all options
burgLabels.selectAll("g").each(function () {
select.options.add(new Option(this.id, this.id, false, this.id === group));
select.options.add(
new Option(this.id, this.id, false, this.id === group)
);
});
// set emlem image
@ -157,7 +240,7 @@ function editBurg(id) {
"Mogadishu",
"Bangkok",
"Aden",
"Khartoum"
"Khartoum",
]; // 21 - 30
if (temperature > 30) return "Mecca";
return cities[temperature + 5] || null;
@ -172,17 +255,25 @@ function editBurg(id) {
const x = d3.event.x,
y = d3.event.y;
this.setAttribute("transform", `translate(${dx + x},${dy + y})`);
tip('Use dragging for fine-tuning only, to actually move burg use "Relocate" button', false, "warning");
tip(
'Use dragging for fine-tuning only, to actually move burg use "Relocate" button',
false,
"warning"
);
});
}
function showGroupSection() {
document.querySelectorAll("#burgBottom > button").forEach(el => (el.style.display = "none"));
document
.querySelectorAll("#burgBottom > button")
.forEach((el) => (el.style.display = "none"));
document.getElementById("burgGroupSection").style.display = "inline-block";
}
function hideGroupSection() {
document.querySelectorAll("#burgBottom > button").forEach(el => (el.style.display = "inline-block"));
document
.querySelectorAll("#burgBottom > button")
.forEach((el) => (el.style.display = "inline-block"));
document.getElementById("burgGroupSection").style.display = "none";
document.getElementById("burgInputGroup").style.display = "none";
document.getElementById("burgInputGroup").value = "";
@ -216,7 +307,11 @@ function editBurg(id) {
.replace(/[^\w\s]/gi, "");
if (document.getElementById(group)) {
tip("Element with this id already exists. Please provide a unique name", false, "error");
tip(
"Element with this id already exists. Please provide a unique name",
false,
"error"
);
return;
}
@ -244,7 +339,9 @@ function editBurg(id) {
const count = elSelected.node().parentNode.childElementCount;
if (oldGroup !== "cities" && oldGroup !== "towns" && count === 1) {
document.getElementById("burgSelectGroup").selectedOptions[0].remove();
document.getElementById("burgSelectGroup").options.add(new Option(group, group, false, true));
document
.getElementById("burgSelectGroup")
.options.add(new Option(group, group, false, true));
toggleNewGroupInput();
document.getElementById("burgInputGroup").value = "";
labelG.id = group;
@ -254,16 +351,24 @@ function editBurg(id) {
}
// create new groups
document.getElementById("burgSelectGroup").options.add(new Option(group, group, false, true));
document
.getElementById("burgSelectGroup")
.options.add(new Option(group, group, false, true));
toggleNewGroupInput();
document.getElementById("burgInputGroup").value = "";
const newLabelG = document.querySelector("#burgLabels").appendChild(labelG.cloneNode(false));
const newLabelG = document
.querySelector("#burgLabels")
.appendChild(labelG.cloneNode(false));
newLabelG.id = group;
const newIconG = document.querySelector("#burgIcons").appendChild(iconG.cloneNode(false));
const newIconG = document
.querySelector("#burgIcons")
.appendChild(iconG.cloneNode(false));
newIconG.id = group;
if (anchor) {
const newAnchorG = document.querySelector("#anchors").appendChild(anchorG.cloneNode(false));
const newAnchorG = document
.querySelector("#anchors")
.appendChild(anchorG.cloneNode(false));
newAnchorG.id = group;
}
moveBurgToGroup(id, group);
@ -277,11 +382,17 @@ function editBurg(id) {
for (let i = 0; i < group.children.length; i++) {
burgsInGroup.push(+group.children[i].dataset.id);
}
const burgsToRemove = burgsInGroup.filter(b => !(pack.burgs[b].capital || pack.burgs[b].lock));
const burgsToRemove = burgsInGroup.filter(
(b) => !(pack.burgs[b].capital || pack.burgs[b].lock)
);
const capital = burgsToRemove.length < burgsInGroup.length;
alertMessage.innerHTML = `Are you sure you want to remove
${basic || capital ? "all unlocked elements in the group" : "the entire burg group"}?
${
basic || capital
? "all unlocked elements in the group"
: "the entire burg group"
}?
<br>Please note that capital or locked burgs will not be deleted.
<br><br>Burgs to be removed: ${burgsToRemove.length}`;
$("#alert").dialog({
@ -292,7 +403,7 @@ function editBurg(id) {
$(this).dialog("close");
$("#burgEditor").dialog("close");
hideGroupSection();
burgsToRemove.forEach(b => removeBurg(b));
burgsToRemove.forEach((b) => removeBurg(b));
if (!basic && !capital) {
// entirely remove group
@ -306,8 +417,8 @@ function editBurg(id) {
},
Cancel: function () {
$(this).dialog("close");
}
}
},
},
});
}
@ -342,7 +453,10 @@ function editBurg(id) {
function changePopulation() {
const id = +elSelected.attr("data-id");
pack.burgs[id].population = rn(burgPopulation.value / populationRate / urbanization, 4);
pack.burgs[id].population = rn(
burgPopulation.value / populationRate / urbanization,
4
);
}
function toggleFeature() {
@ -356,7 +470,9 @@ function editBurg(id) {
if (b[feature]) this.classList.remove("inactive");
else if (!b[feature]) this.classList.add("inactive");
if (b.port) document.getElementById("burgEditAnchorStyle").style.display = "inline-block";
if (b.port)
document.getElementById("burgEditAnchorStyle").style.display =
"inline-block";
else document.getElementById("burgEditAnchorStyle").style.display = "none";
}
@ -379,12 +495,16 @@ function editBurg(id) {
}
function showStyleSection() {
document.querySelectorAll("#burgBottom > button").forEach(el => (el.style.display = "none"));
document
.querySelectorAll("#burgBottom > button")
.forEach((el) => (el.style.display = "none"));
document.getElementById("burgStyleSection").style.display = "inline-block";
}
function hideStyleSection() {
document.querySelectorAll("#burgBottom > button").forEach(el => (el.style.display = "inline-block"));
document
.querySelectorAll("#burgBottom > button")
.forEach((el) => (el.style.display = "inline-block"));
document.getElementById("burgStyleSection").style.display = "none";
}
@ -408,21 +528,25 @@ function editBurg(id) {
const burgGeneratorURL = getBurgLink(burg);
document.getElementById("mfcgPreview").setAttribute("src", mfcgURL);
document.getElementById("mfcgLink").setAttribute("href", mfcgURL);
document.getElementById("burgGenerator").setAttribute("href", burgGeneratorURL);
debug
document
.getElementById("burgGenerator")
.setAttribute("href", burgGeneratorURL);
debug;
}
function getBurgSeed(burg) {
return burg.MFCG || Number(`${seed}${String(burg.i).padStart(4, 0)}`);
}
function getBurgLink(burg) {
const {cells} = pack;
let burgCulture = pack.cultures[burg.culture].name.split('(')[1].split(')')[0];
const { cells } = pack;
let burgCulture = pack.cultures[burg.culture].name
.split("(")[1]
.split(")")[0];
const {name, population, cell} = burg;
const { name, population, cell } = burg;
const burgSeed = getBurgSeed(burg);
const sizeRaw = 0.43 * Math.pow((population * populationRate) / urbanDensity, 0.385);
const sizeRaw =
0.43 * Math.pow((population * populationRate) / urbanDensity, 0.385);
const size = minmax(Math.ceil(sizeRaw), 2, 40);
const people = rn(population * populationRate * urbanization);
const hub = +cells.road[cell] > 50;
@ -435,6 +559,7 @@ function editBurg(id) {
const temple = +burg.temple;
const shanty = +burg.shanty;
const worldName = mapName.value;
const sea = coast && cells.haven[cell] ? getSeaDirections(cell) : "";
function getSeaDirections(i) {
const p1 = cells.p[i];
@ -445,24 +570,23 @@ function editBurg(id) {
return "&sea=" + norm;
}
let townSize = "tiny";
if (people > 200) townSize = 'small';
if (people > 900) townSize = 'medium';
if (people > 2_000) townSize = 'average';
if (people > 5_500) townSize = 'big';
if (people > 200) townSize = "small";
if (people > 900) townSize = "medium";
if (people > 2_000) townSize = "average";
if (people > 5_500) townSize = "big";
const baseURL = "http://localhost:9090/town/";
const url = `${baseURL}${name}-${burgCulture}/${townSize}`;
const url = `${baseURL}${worldName}_${name}-${burgCulture}/${townSize}`;
return url;
}
function getMFCGlink(burg) {
const {cells} = pack;
const {name, population, cell} = burg;
const { cells } = pack;
const { name, population, cell } = burg;
const burgSeed = getBurgSeed(burg);
const sizeRaw = 0.43 * Math.pow((population * populationRate) / urbanDensity, 0.385);
const size = minmax(Math.ceil(sizeRaw), 2, 40)*3;
const sizeRaw =
0.43 * Math.pow((population * populationRate) / urbanDensity, 0.385);
const size = minmax(Math.ceil(sizeRaw), 2, 40) * 3;
const people = rn(population * populationRate * urbanization);
const hub = +cells.road[cell] > 50;
@ -485,7 +609,8 @@ function editBurg(id) {
return "&sea=" + norm;
}
const baseURL = "https://watabou.github.io/city-generator/?random=0&continuous=0";
const baseURL =
"https://watabou.github.io/city-generator/?random=0&continuous=0";
const url = `${baseURL}&name=${name}&population=${people}&size=${size}&seed=${burgSeed}&hub=${hub}&river=${river}&coast=${coast}&citadel=${citadel}&plaza=${plaza}&temple=${temple}&walls=${walls}&shantytown=${shanty}${sea}`;
return url;
}
@ -515,8 +640,11 @@ function editBurg(id) {
function toggleMFCGMap() {
options.showMFCGMap = !options.showMFCGMap;
document.getElementById("mfcgPreviewSection").style.display = options.showMFCGMap ? "block" : "none";
document.getElementById("burgToggleMFCGMap").className = options.showMFCGMap ? "icon-map" : "icon-map-o";
document.getElementById("mfcgPreviewSection").style.display =
options.showMFCGMap ? "block" : "none";
document.getElementById("burgToggleMFCGMap").className = options.showMFCGMap
? "icon-map"
: "icon-map-o";
}
function toggleRelocateBurg() {
@ -524,7 +652,10 @@ function editBurg(id) {
document.getElementById("burgRelocate").classList.toggle("pressed");
if (document.getElementById("burgRelocate").classList.contains("pressed")) {
viewbox.style("cursor", "crosshair").on("click", relocateBurgOnClick);
tip("Click on map to relocate burg. Hold Shift for continuous move", true);
tip(
"Click on map to relocate burg. Hold Shift for continuous move",
true
);
if (!layerIsOn("toggleCells")) {
toggleCells();
toggler.dataset.forced = true;
@ -547,12 +678,20 @@ function editBurg(id) {
const burg = pack.burgs[id];
if (cells.h[cell] < 20) {
tip("Cannot place burg into the water! Select a land cell", false, "error");
tip(
"Cannot place burg into the water! Select a land cell",
false,
"error"
);
return;
}
if (cells.burg[cell] && cells.burg[cell] !== id) {
tip("There is already a burg in this cell. Please select a free cell", false, "error");
tip(
"There is already a burg in this cell. Please select a free cell",
false,
"error"
);
return;
}
@ -614,8 +753,8 @@ function editBurg(id) {
buttons: {
Ok: function () {
$(this).dialog("close");
}
}
},
},
});
} else {
alertMessage.innerHTML = "Are you sure you want to remove the burg?";
@ -630,15 +769,18 @@ function editBurg(id) {
},
Cancel: function () {
$(this).dialog("close");
}
}
},
},
});
}
}
function closeBurgEditor() {
document.getElementById("burgRelocate").classList.remove("pressed");
burgLabels.selectAll("text").call(d3.drag().on("drag", null)).classed("draggable", false);
burgLabels
.selectAll("text")
.call(d3.drag().on("drag", null))
.classed("draggable", false);
unselect();
}
}

View file

@ -7,7 +7,11 @@ restoreDefaultEvents(); // apply default viewbox events on load
// restore default viewbox events
function restoreDefaultEvents() {
svg.call(zoom);
viewbox.style("cursor", "default").on(".drag", null).on("click", clicked).on("touchmove mousemove", moved);
viewbox
.style("cursor", "default")
.on(".drag", null)
.on("click", clicked)
.on("touchmove mousemove", moved);
legend.call(d3.drag().on("start", dragLegendBox));
}
@ -24,7 +28,11 @@ function clicked() {
if (grand.id === "emblems") editEmblem();
else if (parent.id === "rivers") editRiver(el.id);
else if (grand.id === "routes") editRoute();
else if (el.tagName === "tspan" && grand.parentNode.parentNode.id === "labels") editLabel();
else if (
el.tagName === "tspan" &&
grand.parentNode.parentNode.id === "labels"
)
editLabel();
else if (grand.id === "burgLabels") editBurg();
else if (grand.id === "burgIcons") editBurg();
else if (parent.id === "ice") editIce();
@ -71,7 +79,8 @@ function moveCircle(x, y, r = 20) {
}
function removeCircle() {
if (document.getElementById("brushCircle")) document.getElementById("brushCircle").remove();
if (document.getElementById("brushCircle"))
document.getElementById("brushCircle").remove();
}
// get browser-defined fit-content
@ -92,8 +101,8 @@ function sortLines(header) {
if (!header.className.includes("icon-sort") && type === "name") order = "-up";
const headers = header.parentNode;
headers.querySelectorAll("div.sortable").forEach(e => {
e.classList.forEach(c => {
headers.querySelectorAll("div.sortable").forEach((e) => {
e.classList.forEach((c) => {
if (c.includes("icon-sort")) e.classList.remove(c);
});
});
@ -116,7 +125,7 @@ function applySorting(headers) {
const bn = name ? b.dataset[sortby] : +b.dataset[sortby];
return (an > bn ? 1 : an < bn ? -1 : 0) * desc;
})
.forEach(line => list.appendChild(line));
.forEach((line) => list.appendChild(line));
}
function addBurg(point) {
@ -131,7 +140,10 @@ function addBurg(point) {
const feature = cells.f[cell];
const temple = pack.states[state].form === "Theocracy";
const population = Math.max((cells.s[cell] + cells.road[cell]) / 3 + i / 1000 + (cell % 100) / 1000, 0.1);
const population = Math.max(
(cells.s[cell] + cells.road[cell]) / 3 + i / 1000 + (cell % 100) / 1000,
0.1
);
const type = BurgsAndStates.getType(cell, false);
// generate emblem
@ -139,7 +151,22 @@ function addBurg(point) {
coa.shield = COA.getShield(culture, state);
COArenderer.add("burg", i, coa, x, y);
pack.burgs.push({name, cell, x, y, state, i, culture, feature, capital: 0, port: 0, temple, population, coa, type});
pack.burgs.push({
name,
cell,
x,
y,
state,
i,
culture,
feature,
capital: 0,
port: 0,
temple,
population,
coa,
type,
});
cells.burg[cell] = i;
const townSize = burgIcons.select("#towns").attr("size") || 0.5;
@ -219,7 +246,11 @@ function toggleCapital(burg) {
return;
}
if (pack.burgs[burg].capital) {
tip("To change capital please assign a capital status to another burg of this state", false, "error");
tip(
"To change capital please assign a capital status to another burg of this state",
false,
"error"
);
return;
}
const old = pack.states[state].capital;
@ -244,7 +275,12 @@ function togglePort(burg) {
const haven = pack.cells.haven[b.cell];
const port = haven ? pack.cells.f[haven] : -1;
if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, "warn");
if (!haven)
tip(
"Port haven is not found, system won't be able to make a searoute",
false,
"warn"
);
b.port = port;
const g = b.capital ? "cities" : "towns";
@ -281,13 +317,22 @@ function drawLegend(name, data) {
const vOffset = fontSize / 2;
// append items
const boxes = legend.append("g").attr("stroke-width", 0.5).attr("stroke", "#111111").attr("stroke-dasharray", "none");
const labels = legend.append("g").attr("fill", "#000000").attr("stroke", "none");
const boxes = legend
.append("g")
.attr("stroke-width", 0.5)
.attr("stroke", "#111111")
.attr("stroke-dasharray", "none");
const labels = legend
.append("g")
.attr("fill", "#000000")
.attr("stroke", "none");
const columns = Math.ceil(data.length / itemsInCol);
for (let column = 0, i = 0; column < columns; column++) {
const linesInColumn = Math.ceil(data.length / columns);
const offset = column ? colOffset * 2 + legend.node().getBBox().width : colOffset;
const offset = column
? colOffset * 2 + legend.node().getBBox().width
: colOffset;
for (let l = 0; l < linesInColumn && data[i]; l++, i++) {
boxes
@ -354,7 +399,7 @@ function redrawLegend() {
const data = legend
.attr("data")
.split("|")
.map(l => l.split(","));
.map((l) => l.split(","));
drawLegend(name, data);
}
@ -383,7 +428,12 @@ function createPicker() {
const cl = () => tip("Click to close the picker");
const closePicker = () => contaiter.style("display", "none");
const contaiter = d3.select("body").append("svg").attr("id", "pickerContainer").attr("width", "100%").attr("height", "100%");
const contaiter = d3
.select("body")
.append("svg")
.attr("id", "pickerContainer")
.attr("width", "100%")
.attr("height", "100%");
contaiter
.append("rect")
.attr("x", 0)
@ -407,19 +457,39 @@ function createPicker() {
const h = controls.append("g");
h.append("text").attr("x", 4).attr("y", 14).text("H:");
h.append("line").attr("x1", 18).attr("y1", 10).attr("x2", 107).attr("y2", 10);
h.append("circle").attr("cx", 75).attr("cy", 10).attr("r", 5).attr("id", "pickerH");
h.append("circle")
.attr("cx", 75)
.attr("cy", 10)
.attr("r", 5)
.attr("id", "pickerH");
h.on("mousemove", () => tip("Set palette hue"));
const s = controls.append("g");
s.append("text").attr("x", 113).attr("y", 14).text("S:");
s.append("line").attr("x1", 124).attr("y1", 10).attr("x2", 206).attr("y2", 10);
s.append("circle").attr("cx", 181.4).attr("cy", 10).attr("r", 5).attr("id", "pickerS");
s.append("line")
.attr("x1", 124)
.attr("y1", 10)
.attr("x2", 206)
.attr("y2", 10);
s.append("circle")
.attr("cx", 181.4)
.attr("cy", 10)
.attr("r", 5)
.attr("id", "pickerS");
s.on("mousemove", () => tip("Set palette saturation"));
const l = controls.append("g");
l.append("text").attr("x", 213).attr("y", 14).text("L:");
l.append("line").attr("x1", 226).attr("y1", 10).attr("x2", 306).attr("y2", 10);
l.append("circle").attr("cx", 282).attr("cy", 10).attr("r", 5).attr("id", "pickerL");
l.append("line")
.attr("x1", 226)
.attr("y1", 10)
.attr("x2", 306)
.attr("y2", 10);
l.append("circle")
.attr("cx", 282)
.attr("cy", 10)
.attr("r", 5)
.attr("id", "pickerL");
l.on("mousemove", () => tip("Set palette lightness"));
controls.selectAll("line").on("click", clickPickerControl);
@ -432,7 +502,9 @@ function createPicker() {
.attr("y", 20)
.attr("width", 303)
.attr("height", 20)
.on("mousemove", () => tip("Color value in different color spaces. Edit to change"));
.on("mousemove", () =>
tip("Color value in different color spaces. Edit to change")
);
const html = `
<label style="margin-right: 6px">HSL:
<input type="number" id="pickerHSL_H" data-space="hsl" min=0 max=360 value="231">,
@ -448,12 +520,20 @@ function createPicker() {
spaces.node().insertAdjacentHTML("beforeend", html);
spaces.selectAll("input").on("change", changePickerSpace);
const colors = picker.append("g").attr("id", "pickerColors").attr("stroke", "#333333");
const hatches = picker.append("g").attr("id", "pickerHatches").attr("stroke", "#333333");
const colors = picker
.append("g")
.attr("id", "pickerColors")
.attr("stroke", "#333333");
const hatches = picker
.append("g")
.attr("id", "pickerHatches")
.attr("stroke", "#333333");
const hatching = d3.selectAll("g#hatching > pattern");
const number = hatching.size();
const clr = d3.range(number).map(i => d3.hsl((i / number) * 360, 0.7, 0.7).hex());
const clr = d3
.range(number)
.map((i) => d3.hsl((i / number) * 360, 0.7, 0.7).hex());
clr.forEach(function (d, i) {
colors
.append("rect")
@ -500,7 +580,12 @@ function createPicker() {
.attr("fill", "#ffffff")
.attr("stroke", "#5d4651")
.on("mousemove", pos);
picker.insert("text", ":first-child").attr("x", 291).attr("y", -10).attr("id", "pickerCloseText").text("✕");
picker
.insert("text", ":first-child")
.attr("x", 291)
.attr("y", -10)
.attr("id", "pickerCloseText")
.text("✕");
picker
.insert("rect", ":first-child")
.attr("x", 288)
@ -510,13 +595,32 @@ function createPicker() {
.attr("height", 14)
.on("mousemove", cl)
.on("click", closePicker);
picker.insert("text", ":first-child").attr("x", 12).attr("y", -10).attr("id", "pickerLabel").text("Color Picker").on("mousemove", pos);
picker.insert("rect", ":first-child").attr("x", 0).attr("y", -30).attr("width", width).attr("height", 30).attr("id", "pickerHeader").on("mousemove", pos);
picker.attr("transform", `translate(${(svgWidth - width) / 2},${(svgHeight - height) / 2})`);
picker
.insert("text", ":first-child")
.attr("x", 12)
.attr("y", -10)
.attr("id", "pickerLabel")
.text("Color Picker")
.on("mousemove", pos);
picker
.insert("rect", ":first-child")
.attr("x", 0)
.attr("y", -30)
.attr("width", width)
.attr("height", 30)
.attr("id", "pickerHeader")
.on("mousemove", pos);
picker.attr(
"transform",
`translate(${(svgWidth - width) / 2},${(svgHeight - height) / 2})`
);
}
function updateSelectedRect(fill) {
document.getElementById("picker").querySelector("rect.selected").classList.remove("selected");
document
.getElementById("picker")
.querySelector("rect.selected")
.classList.remove("selected");
document
.getElementById("picker")
.querySelector("rect[fill='" + fill.toLowerCase() + "']")
@ -574,7 +678,9 @@ function openPicker(fill, callback) {
updateSelectedRect(fill);
openPicker.updateFill = function () {
const selected = document.getElementById("picker").querySelector("rect.selected");
const selected = document
.getElementById("picker")
.querySelector("rect.selected");
if (!selected) return;
callback(selected.getAttribute("fill"));
};
@ -649,8 +755,15 @@ function changePickerSpace() {
}
const space = this.dataset.space;
const i = Array.from(this.parentNode.querySelectorAll("input")).map(input => input.value); // inputs
const fill = space === "hex" ? d3.rgb(this.value) : space === "rgb" ? d3.rgb(i[0], i[1], i[2]) : d3.hsl(i[0], i[1] / 100, i[2] / 100);
const i = Array.from(this.parentNode.querySelectorAll("input")).map(
(input) => input.value
); // inputs
const fill =
space === "hex"
? d3.rgb(this.value)
: space === "rgb"
? d3.rgb(i[0], i[1], i[2])
: d3.hsl(i[0], i[1] / 100, i[2] / 100);
const hsl = d3.hsl(fill);
if (isNaN(hsl.l)) {
@ -671,11 +784,27 @@ function fog(id, path) {
if (defs.select("#fog #" + id).size()) return;
const fadeIn = d3.transition().duration(2000).ease(d3.easeSinInOut);
if (defs.select("#fog path").size()) {
defs.select("#fog").append("path").attr("d", path).attr("id", id).attr("opacity", 0).transition(fadeIn).attr("opacity", 1);
defs
.select("#fog")
.append("path")
.attr("d", path)
.attr("id", id)
.attr("opacity", 0)
.transition(fadeIn)
.attr("opacity", 1);
} else {
defs.select("#fog").append("path").attr("d", path).attr("id", id).attr("opacity", 1);
defs
.select("#fog")
.append("path")
.attr("d", path)
.attr("id", id)
.attr("opacity", 1);
const opacity = fogging.attr("opacity");
fogging.style("display", "block").attr("opacity", 0).transition(fadeIn).attr("opacity", opacity);
fogging
.style("display", "block")
.attr("opacity", 0)
.transition(fadeIn)
.attr("opacity", opacity);
}
}
@ -689,7 +818,7 @@ function unfog(id) {
}
function getFileName(dataType) {
const formatTime = time => (time < 10 ? "0" + time : time);
const formatTime = (time) => (time < 10 ? "0" + time : time);
const name = mapName.value;
const type = dataType ? dataType + " " : "";
const date = new Date();
@ -699,11 +828,13 @@ function getFileName(dataType) {
const hour = formatTime(date.getHours());
const minutes = formatTime(date.getMinutes());
const dateString = [year, month, day, hour, minutes].join("-");
return name + " " + type + dateString;
//return name + " " + type + dateString;
return name;
}
function downloadFile(data, name, type = "text/plain") {
const dataBlob = new Blob([data], {type});
const dataBlob = new Blob([data], { type });
const url = window.URL.createObjectURL(dataBlob);
const link = document.createElement("a");
link.download = name;
@ -716,7 +847,7 @@ function uploadFile(el, callback) {
const fileReader = new FileReader();
fileReader.readAsText(el.files[0], "UTF-8");
el.value = "";
fileReader.onload = loaded => callback(loaded.target.result);
fileReader.onload = (loaded) => callback(loaded.target.result);
}
function getBBox(element) {
@ -724,7 +855,7 @@ function getBBox(element) {
const y = +element.getAttribute("y");
const width = +element.getAttribute("width");
const height = +element.getAttribute("height");
return {x, y, width, height};
return { x, y, width, height };
}
function highlightElement(element, zoom) {
@ -734,9 +865,20 @@ function highlightElement(element, zoom) {
const enter = d3.transition().duration(1000).ease(d3.easeBounceOut);
const exit = d3.transition().duration(500).ease(d3.easeLinear);
const highlight = debug.append("rect").attr("x", box.x).attr("y", box.y).attr("width", box.width).attr("height", box.height);
const highlight = debug
.append("rect")
.attr("x", box.x)
.attr("y", box.y)
.attr("width", box.width)
.attr("height", box.height);
highlight.classed("highlighted", 1).attr("transform", transform);
highlight.transition(enter).style("outline-offset", "0px").transition(exit).style("outline-color", "transparent").delay(1000).remove();
highlight
.transition(enter)
.style("outline-offset", "0px")
.transition(exit)
.style("outline-color", "transparent")
.delay(1000)
.remove();
if (zoom) {
const tr = parseTransform(transform);
@ -944,7 +1086,7 @@ function selectIcon(initial, callback) {
"🍻",
"🍺",
"🍲",
"🍷"
"🍷",
];
let row = "";
@ -955,15 +1097,16 @@ function selectIcon(initial, callback) {
}
}
input.oninput = e => callback(input.value);
table.onclick = e => {
input.oninput = (e) => callback(input.value);
table.onclick = (e) => {
if (e.target.tagName === "TD") {
input.value = e.target.innerHTML;
callback(input.value);
}
};
table.onmouseover = e => {
if (e.target.tagName === "TD") tip(`Click to select ${e.target.innerHTML} icon`);
table.onmouseover = (e) => {
if (e.target.tagName === "TD")
tip(`Click to select ${e.target.innerHTML} icon`);
};
$("#iconSelector").dialog({
@ -977,8 +1120,8 @@ function selectIcon(initial, callback) {
Close: function () {
callback(initial);
$(this).dialog("close");
}
}
},
},
});
}
@ -989,7 +1132,7 @@ function confirmationDialog(options) {
cancel = "Cancel",
confirm = "Continue",
onCancel,
onConfirm
onConfirm,
} = options;
const buttons = {
@ -1000,11 +1143,11 @@ function confirmationDialog(options) {
[cancel]: function () {
if (onCancel) onCancel();
$(this).dialog("close");
}
},
};
document.getElementById("alertMessage").innerHTML = message;
$("#alert").dialog({resizable: false, title, buttons});
$("#alert").dialog({ resizable: false, title, buttons });
}
// add and register event listeners to clean up on editor closure
@ -1016,12 +1159,19 @@ function listen(element, event, handler) {
// Calls the refresh functionality on all editors currently open.
function refreshAllEditors() {
TIME && console.time("refreshAllEditors");
if (document.getElementById("culturesEditorRefresh").offsetParent) culturesEditorRefresh.click();
if (document.getElementById("biomesEditorRefresh").offsetParent) biomesEditorRefresh.click();
if (document.getElementById("diplomacyEditorRefresh").offsetParent) diplomacyEditorRefresh.click();
if (document.getElementById("provincesEditorRefresh").offsetParent) provincesEditorRefresh.click();
if (document.getElementById("religionsEditorRefresh").offsetParent) religionsEditorRefresh.click();
if (document.getElementById("statesEditorRefresh").offsetParent) statesEditorRefresh.click();
if (document.getElementById("zonesEditorRefresh").offsetParent) zonesEditorRefresh.click();
if (document.getElementById("culturesEditorRefresh").offsetParent)
culturesEditorRefresh.click();
if (document.getElementById("biomesEditorRefresh").offsetParent)
biomesEditorRefresh.click();
if (document.getElementById("diplomacyEditorRefresh").offsetParent)
diplomacyEditorRefresh.click();
if (document.getElementById("provincesEditorRefresh").offsetParent)
provincesEditorRefresh.click();
if (document.getElementById("religionsEditorRefresh").offsetParent)
religionsEditorRefresh.click();
if (document.getElementById("statesEditorRefresh").offsetParent)
statesEditorRefresh.click();
if (document.getElementById("zonesEditorRefresh").offsetParent)
zonesEditorRefresh.click();
TIME && console.timeEnd("refreshAllEditors");
}

View file

@ -3,13 +3,18 @@
// fit full-screen map if window is resized
window.addEventListener("resize", function (e) {
if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) return;
if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight"))
return;
mapWidthInput.value = window.innerWidth;
mapHeightInput.value = window.innerHeight;
changeMapSize();
});
if (location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1") {
if (
location.hostname &&
location.hostname !== "localhost" &&
location.hostname !== "127.0.0.1"
) {
window.onbeforeunload = () => "Are you sure you want to navigate away?";
}
@ -18,15 +23,26 @@ const tooltip = document.getElementById("tooltip");
// show tip for non-svg elemets with data-tip
document.getElementById("dialogs").addEventListener("mousemove", showDataTip);
document.getElementById("optionsContainer").addEventListener("mousemove", showDataTip);
document.getElementById("exitCustomization").addEventListener("mousemove", showDataTip);
document
.getElementById("optionsContainer")
.addEventListener("mousemove", showDataTip);
document
.getElementById("exitCustomization")
.addEventListener("mousemove", showDataTip);
function tip(tip = "Tip is undefined", main, type, time) {
tooltip.innerHTML = tip;
tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)";
if (type === "error") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #e11d1dcc, #ffffff00)";
else if (type === "warn") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #be5d08cc, #ffffff00)";
else if (type === "success") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)";
tooltip.style.background =
"linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)";
if (type === "error")
tooltip.style.background =
"linear-gradient(0.1turn, #ffffff00, #e11d1dcc, #ffffff00)";
else if (type === "warn")
tooltip.style.background =
"linear-gradient(0.1turn, #ffffff00, #be5d08cc, #ffffff00)";
else if (type === "success")
tooltip.style.background =
"linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)";
if (main) {
tooltip.dataset.main = tip;
@ -50,7 +66,8 @@ function clearMainTip() {
function showDataTip(e) {
if (!e.target) return;
let dataTip = e.target.dataset.tip;
if (!dataTip && e.target.parentNode.dataset.tip) dataTip = e.target.parentNode.dataset.tip;
if (!dataTip && e.target.parentNode.dataset.tip)
dataTip = e.target.parentNode.dataset.tip;
if (!dataTip) return;
//const tooltip = lang === "en" ? dataTip : translate(e.target.dataset.t || e.target.parentNode.dataset.t, dataTip);
tip(dataTip);
@ -59,9 +76,13 @@ function showDataTip(e) {
function showElementLockTip(event) {
const locked = event?.target?.classList?.contains("icon-lock");
if (locked) {
tip("Click to unlock the element and allow it to be changed by regeneration tools");
tip(
"Click to unlock the element and allow it to be changed by regeneration tools"
);
} else {
tip("Click to lock the element and prevent changes to it by regeneration tools");
tip(
"Click to lock the element and prevent changes to it by regeneration tools"
);
}
}
@ -80,11 +101,14 @@ function mouseMove() {
// show note box on hover (if any)
function showNotes(e, i) {
if (notesEditor.offsetParent) return;
let id = e.target.id || e.target.parentNode.id || e.target.parentNode.parentNode.id;
if (e.target.parentNode.parentNode.id === "burgLabels") id = "burg" + e.target.dataset.id;
else if (e.target.parentNode.parentNode.id === "burgIcons") id = "burg" + e.target.dataset.id;
let id =
e.target.id || e.target.parentNode.id || e.target.parentNode.parentNode.id;
if (e.target.parentNode.parentNode.id === "burgLabels")
id = "burg" + e.target.dataset.id;
else if (e.target.parentNode.parentNode.id === "burgIcons")
id = "burg" + e.target.dataset.id;
const note = notes.find(note => note.id === id);
const note = notes.find((note) => note.id === id);
if (note !== undefined && note.legend !== "") {
document.getElementById("notes").style.display = "block";
document.getElementById("notesHeader").innerHTML = note.name;
@ -96,6 +120,34 @@ function showNotes(e, i) {
}
}
function createMetaTip(point, e, i, g) {
const biome = pack.cells.biome[i];
const religion = pack.cells.religion[i];
const r = pack.religions[religion];
const religionType =
r.type === "Cult" || r.type == "Heresy" ? r.type : r.type + " religion";
const state = pack.cells.state[i];
const stateCulture = pack.cells.state[i].culture;
const stateName = pack.states[state].fullName;
const province = pack.cells.province[i];
const prov = province ? pack.provinces[province].fullName + ", " : "";
const culture = pack.cells.culture[i];
tip("Culture: " + pack.cultures[culture].name);
let tipText =
pack.cultures[culture].name +
" | " +
religionType +
": " +
r.name +
" | " +
stateName +
" - " +
prov +
" | Biome: " +
biomesData.name[biome];
tip(tipText);
}
// show viewbox tooltip if main tooltip is blank
function showMapTooltip(point, e, i, g) {
tip(""); // clear tip
@ -106,12 +158,17 @@ function showMapTooltip(point, e, i, g) {
const land = pack.cells.h[i] >= 20;
// specific elements
if (group === "armies") return tip(e.target.parentNode.dataset.name + ". Click to edit");
if (group === "armies")
return tip(e.target.parentNode.dataset.name + ". Click to edit");
if (group === "emblems" && e.target.tagName === "use") {
const parent = e.target.parentNode;
const [g, type] =
parent.id === "burgEmblems" ? [pack.burgs, "burg"] : parent.id === "provinceEmblems" ? [pack.provinces, "province"] : [pack.states, "state"];
parent.id === "burgEmblems"
? [pack.burgs, "burg"]
: parent.id === "provinceEmblems"
? [pack.provinces, "province"]
: [pack.states, "state"];
const i = +e.target.dataset.i;
if (event.shiftKey) highlightEmblemElement(type, g[i]);
@ -119,16 +176,19 @@ function showMapTooltip(point, e, i, g) {
d3.select(parent).raise();
const name = g[i].fullName || g[i].name;
tip(`${name} ${type} emblem. Click to edit. Hold Shift to show associated area or place`);
tip(
`${name} ${type} emblem. Click to edit. Hold Shift to show associated area or place`
);
return;
}
if (group === "rivers") {
const river = +e.target.id.slice(5);
const r = pack.rivers.find(r => r.i === river);
const r = pack.rivers.find((r) => r.i === river);
const name = r ? r.name + " " + r.type : "";
tip(name + ". Click to edit");
if (riversOverview.offsetParent) highlightEditorLine(riversOverview, river, 5000);
if (riversOverview.offsetParent)
highlightEditorLine(riversOverview, river, 5000);
return;
}
@ -141,22 +201,31 @@ function showMapTooltip(point, e, i, g) {
const b = pack.burgs[burg];
const population = si(b.population * populationRate * urbanization);
tip(`${b.name}. Population: ${population}. Click to edit`);
if (burgsOverview.offsetParent) highlightEditorLine(burgsOverview, burg, 5000);
if (burgsOverview.offsetParent)
highlightEditorLine(burgsOverview, burg, 5000);
return;
}
if (group === "labels") return tip("Click to edit the Label");
if (group === "markers") return tip("Click to edit the Marker and pin the marker note");
if (group === "markers")
return tip("Click to edit the Marker and pin the marker note");
if (group === "ruler") {
const tag = e.target.tagName;
const className = e.target.getAttribute("class");
if (tag === "circle" && className === "edge") return tip("Drag to adjust. Hold Ctrl and drag to add a point. Click to remove the point");
if (tag === "circle" && className === "control") return tip("Drag to adjust. Hold Shift and drag to keep axial direction. Click to remove the point");
if (tag === "circle" && className === "edge")
return tip(
"Drag to adjust. Hold Ctrl and drag to add a point. Click to remove the point"
);
if (tag === "circle" && className === "control")
return tip(
"Drag to adjust. Hold Shift and drag to keep axial direction. Click to remove the point"
);
if (tag === "circle") return tip("Drag to adjust the measurer");
if (tag === "polyline") return tip("Click on drag to add a control point");
if (tag === "path") return tip("Drag to move the measurer");
if (tag === "text") return tip("Drag to move, click to remove the measurer");
if (tag === "text")
return tip("Drag to move, click to remove the measurer");
}
if (subgroup === "burgIcons") return tip("Click to edit the Burg");
@ -175,46 +244,55 @@ function showMapTooltip(point, e, i, g) {
if (group === "zones") {
const zone = path[path.length - 8];
tip(zone.dataset.description);
if (zonesEditor.offsetParent) highlightEditorLine(zonesEditor, zone.id, 5000);
if (zonesEditor.offsetParent)
highlightEditorLine(zonesEditor, zone.id, 5000);
return;
}
if (group === "ice") return tip("Click to edit the Ice");
// covering elements
if (layerIsOn("togglePrec") && land) tip("Annual Precipitation: " + getFriendlyPrecipitation(i));
if (layerIsOn("togglePrec") && land)
tip("Annual Precipitation: " + getFriendlyPrecipitation(i));
else if (layerIsOn("togglePopulation")) tip(getPopulationTip(i));
else if (layerIsOn("toggleTemp")) tip("Temperature: " + convertTemperature(grid.cells.temp[g]));
else if (layerIsOn("toggleTemp"))
tip("Temperature: " + convertTemperature(grid.cells.temp[g]));
else if (layerIsOn("toggleBiomes") && pack.cells.biome[i]) {
const biome = pack.cells.biome[i];
tip("Biome: " + biomesData.name[biome]);
createMetaTip(point, e, i, g);
if (biomesEditor.offsetParent) highlightEditorLine(biomesEditor, biome);
} else if (layerIsOn("toggleReligions") && pack.cells.religion[i]) {
const religion = pack.cells.religion[i];
const r = pack.religions[religion];
const type = r.type === "Cult" || r.type == "Heresy" ? r.type : r.type + " religion";
tip(type + ": " + r.name);
if (religionsEditor.offsetParent) highlightEditorLine(religionsEditor, religion);
} else if (pack.cells.state[i] && (layerIsOn("toggleProvinces") || layerIsOn("toggleStates"))) {
const state = pack.cells.state[i];
const stateName = pack.states[state].fullName;
const province = pack.cells.province[i];
const prov = province ? pack.provinces[province].fullName + ", " : "";
tip(prov + stateName);
createMetaTip(point, e, i, g);
if (religionsEditor.offsetParent)
highlightEditorLine(religionsEditor, religion);
} else if (
pack.cells.state[i] &&
(layerIsOn("toggleProvinces") || layerIsOn("toggleStates"))
) {
createMetaTip(point, e, i, g);
if (statesEditor.offsetParent) highlightEditorLine(statesEditor, state);
if (diplomacyEditor.offsetParent) highlightEditorLine(diplomacyEditor, state);
if (militaryOverview.offsetParent) highlightEditorLine(militaryOverview, state);
if (provincesEditor.offsetParent) highlightEditorLine(provincesEditor, province);
if (diplomacyEditor.offsetParent)
highlightEditorLine(diplomacyEditor, state);
if (militaryOverview.offsetParent)
highlightEditorLine(militaryOverview, state);
if (provincesEditor.offsetParent)
highlightEditorLine(provincesEditor, province);
} else if (layerIsOn("toggleCultures") && pack.cells.culture[i]) {
const culture = pack.cells.culture[i];
tip("Culture: " + pack.cultures[culture].name);
if (culturesEditor.offsetParent) highlightEditorLine(culturesEditor, culture);
} else if (layerIsOn("toggleHeight")) tip("Height: " + getFriendlyHeight(point));
createMetaTip(point, e, i, g);
if (culturesEditor.offsetParent) {
highlightEditorLine(culturesEditor, culture);
}
} else if (layerIsOn("toggleHeight"))
tip("Height: " + getFriendlyHeight(point));
}
function highlightEditorLine(editor, id, timeout = 15000) {
Array.from(editor.getElementsByClassName("states hovered")).forEach(el => el.classList.remove("hovered")); // clear all hovered
const hovered = Array.from(editor.querySelectorAll("div")).find(el => el.dataset.id == id);
Array.from(editor.getElementsByClassName("states hovered")).forEach((el) =>
el.classList.remove("hovered")
); // clear all hovered
const hovered = Array.from(editor.querySelectorAll("div")).find(
(el) => el.dataset.id == id
);
if (hovered) hovered.classList.add("hovered"); // add hovered class
if (timeout)
setTimeout(() => {
@ -228,23 +306,48 @@ function updateCellInfo(point, i, g) {
const x = (infoX.innerHTML = rn(point[0]));
const y = (infoY.innerHTML = rn(point[1]));
const f = cells.f[i];
infoLat.innerHTML = toDMS(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT, "lat");
infoLon.innerHTML = toDMS(mapCoordinates.lonW + (x / graphWidth) * mapCoordinates.lonT, "lon");
infoLat.innerHTML = toDMS(
mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT,
"lat"
);
infoLon.innerHTML = toDMS(
mapCoordinates.lonW + (x / graphWidth) * mapCoordinates.lonT,
"lon"
);
infoCell.innerHTML = i;
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
infoArea.innerHTML = cells.area[i] ? si(cells.area[i] * distanceScaleInput.value ** 2) + unit : "n/a";
const unit =
areaUnit.value === "square"
? " " + distanceUnitInput.value + "²"
: " " + areaUnit.value;
infoArea.innerHTML = cells.area[i]
? si(cells.area[i] * distanceScaleInput.value ** 2) + unit
: "n/a";
infoEvelation.innerHTML = getElevation(pack.features[f], pack.cells.h[i]);
infoDepth.innerHTML = getDepth(pack.features[f], pack.cells.h[i], point);
infoTemp.innerHTML = convertTemperature(grid.cells.temp[g]);
infoPrec.innerHTML = cells.h[i] >= 20 ? getFriendlyPrecipitation(i) : "n/a";
infoRiver.innerHTML = cells.h[i] >= 20 && cells.r[i] ? getRiverInfo(cells.r[i]) : "no";
infoState.innerHTML = cells.h[i] >= 20 ? (cells.state[i] ? `${pack.states[cells.state[i]].fullName} (${cells.state[i]})` : "neutral lands (0)") : "no";
infoProvince.innerHTML = cells.province[i] ? `${pack.provinces[cells.province[i]].fullName} (${cells.province[i]})` : "no";
infoCulture.innerHTML = cells.culture[i] ? `${pack.cultures[cells.culture[i]].name} (${cells.culture[i]})` : "no";
infoReligion.innerHTML = cells.religion[i] ? `${pack.religions[cells.religion[i]].name} (${cells.religion[i]})` : "no";
infoRiver.innerHTML =
cells.h[i] >= 20 && cells.r[i] ? getRiverInfo(cells.r[i]) : "no";
infoState.innerHTML =
cells.h[i] >= 20
? cells.state[i]
? `${pack.states[cells.state[i]].fullName} (${cells.state[i]})`
: "neutral lands (0)"
: "no";
infoProvince.innerHTML = cells.province[i]
? `${pack.provinces[cells.province[i]].fullName} (${cells.province[i]})`
: "no";
infoCulture.innerHTML = cells.culture[i]
? `${pack.cultures[cells.culture[i]].name} (${cells.culture[i]})`
: "no";
infoReligion.innerHTML = cells.religion[i]
? `${pack.religions[cells.religion[i]].name} (${cells.religion[i]})`
: "no";
infoPopulation.innerHTML = getFriendlyPopulation(i);
infoBurg.innerHTML = cells.burg[i] ? pack.burgs[cells.burg[i]].name + " (" + cells.burg[i] + ")" : "no";
infoBurg.innerHTML = cells.burg[i]
? pack.burgs[cells.burg[i]].name + " (" + cells.burg[i] + ")"
: "no";
infoFeature.innerHTML = f ? pack.features[f].group + " (" + f + ")" : "n/a";
infoBiome.innerHTML = biomesData.name[cells.biome[i]];
}
@ -255,7 +358,8 @@ function toDMS(coord, c) {
const minutesNotTruncated = (Math.abs(coord) - degrees) * 60;
const minutes = Math.floor(minutesNotTruncated);
const seconds = Math.floor((minutesNotTruncated - minutes) * 60);
const cardinal = c === "lat" ? (coord >= 0 ? "N" : "S") : coord >= 0 ? "E" : "W";
const cardinal =
c === "lat" ? (coord >= 0 ? "N" : "S") : coord >= 0 ? "E" : "W";
return degrees + "° " + minutes + " " + seconds + "″ " + cardinal;
}
@ -310,13 +414,15 @@ function getFriendlyPrecipitation(i) {
}
function getRiverInfo(id) {
const r = pack.rivers.find(r => r.i == id);
const r = pack.rivers.find((r) => r.i == id);
return r ? `${r.name} ${r.type} (${id})` : "n/a";
}
function getCellPopulation(i) {
const rural = pack.cells.pop[i] * populationRate;
const urban = pack.cells.burg[i] ? pack.burgs[pack.cells.burg[i]].population * populationRate * urbanization : 0;
const urban = pack.cells.burg[i]
? pack.burgs[pack.cells.burg[i]].population * populationRate * urbanization
: 0;
return [rural, urban];
}
@ -328,7 +434,9 @@ function getFriendlyPopulation(i) {
function getPopulationTip(i) {
const [rural, urban] = getCellPopulation(i);
return `Cell population: ${si(rural + urban)}; Rural: ${si(rural)}; Urban: ${si(urban)}`;
return `Cell population: ${si(rural + urban)}; Rural: ${si(
rural
)}; Urban: ${si(urban)}`;
}
function highlightEmblemElement(type, el) {
@ -337,7 +445,7 @@ function highlightEmblemElement(type, el) {
const animation = d3.transition().duration(1000).ease(d3.easeSinIn);
if (type === "burg") {
const {x, y} = el;
const { x, y } = el;
debug
.append("circle")
.attr("cx", x)
@ -357,11 +465,13 @@ function highlightEmblemElement(type, el) {
const [x, y] = el.pole || pack.cells.p[el.center];
const obj = type === "state" ? cells.state : cells.province;
const borderCells = cells.i.filter(id => obj[id] === i && cells.c[id].some(n => obj[n] !== i));
const borderCells = cells.i.filter(
(id) => obj[id] === i && cells.c[id].some((n) => obj[n] !== i)
);
const data = Array.from(borderCells)
.filter((c, i) => !(i % 2))
.map(i => cells.p[i])
.map(i => [i[0], i[1], Math.hypot(i[0] - x, i[1] - y)]);
.map((i) => cells.p[i])
.map((i) => [i[0], i[1], Math.hypot(i[0] - x, i[1] - y)]);
debug
.selectAll("line")
@ -370,19 +480,19 @@ function highlightEmblemElement(type, el) {
.append("line")
.attr("x1", x)
.attr("y1", y)
.attr("x2", d => d[0])
.attr("y2", d => d[1])
.attr("x2", (d) => d[0])
.attr("y2", (d) => d[1])
.attr("stroke", "#d0240f")
.attr("stroke-width", 0.5)
.attr("opacity", 0.2)
.attr("stroke-dashoffset", d => d[2])
.attr("stroke-dasharray", d => d[2])
.attr("stroke-dashoffset", (d) => d[2])
.attr("stroke-dasharray", (d) => d[2])
.transition(animation)
.attr("stroke-dashoffset", 0)
.attr("opacity", 1)
.transition(animation)
.delay(1000)
.attr("stroke-dashoffset", d => d[2])
.attr("stroke-dashoffset", (d) => d[2])
.attr("opacity", 0)
.remove();
}
@ -390,8 +500,14 @@ function highlightEmblemElement(type, el) {
// assign lock behavior
document.querySelectorAll("[data-locked]").forEach(function (e) {
e.addEventListener("mouseover", function (event) {
if (this.className === "icon-lock") tip("Click to unlock the option and allow it to be randomized on new map generation");
else tip("Click to lock the option and always use the current value on new map generation");
if (this.className === "icon-lock")
tip(
"Click to unlock the option and allow it to be randomized on new map generation"
);
else
tip(
"Click to lock the option and always use the current value on new map generation"
);
event.stopPropagation();
});
@ -433,7 +549,7 @@ function stored(option) {
}
// assign skeaker behaviour
Array.from(document.getElementsByClassName("speaker")).forEach(el => {
Array.from(document.getElementsByClassName("speaker")).forEach((el) => {
const input = el.previousElementSibling;
el.addEventListener("click", () => speak(input.value));
});
@ -450,7 +566,7 @@ function speak(text) {
// apply drop-down menu option. If the value is not in options, add it
function applyOption(select, id, name = id) {
const custom = !Array.from(select.options).some(o => o.value == id);
const custom = !Array.from(select.options).some((o) => o.value == id);
if (custom) select.options.add(new Option(name, id));
select.value = id;
}
@ -460,11 +576,20 @@ function showInfo() {
const Discord = link("https://discordapp.com/invite/X7E84HU", "Discord");
const Reddit = link("https://www.reddit.com/r/FantasyMapGenerator", "Reddit");
const Patreon = link("https://www.patreon.com/azgaar", "Patreon");
const Trello = link("https://trello.com/b/7x832DG4/fantasy-map-generator", "Trello");
const Trello = link(
"https://trello.com/b/7x832DG4/fantasy-map-generator",
"Trello"
);
const Armoria = link("https://azgaar.github.io/Armoria", "Armoria");
const QuickStart = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Quick-Start-Tutorial", "Quick start tutorial");
const QAA = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A", "Q&A page");
const QuickStart = link(
"https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Quick-Start-Tutorial",
"Quick start tutorial"
);
const QAA = link(
"https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A",
"Q&A page"
);
alertMessage.innerHTML = `
<b>Fantasy Map Generator</b> (FMG) is an open-source application, it means the code is published an anyone can use it.
@ -482,10 +607,22 @@ function showInfo() {
<b>Links:</b>
<ul style="columns:2">
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator", "GitHub repository")}</li>
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator/blob/master/LICENSE", "License")}</li>
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog", "Changelog")}</li>
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys", "Hotkeys")}</li>
<li>${link(
"https://github.com/Azgaar/Fantasy-Map-Generator",
"GitHub repository"
)}</li>
<li>${link(
"https://github.com/Azgaar/Fantasy-Map-Generator/blob/master/LICENSE",
"License"
)}</li>
<li>${link(
"https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog",
"Changelog"
)}</li>
<li>${link(
"https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys",
"Hotkeys"
)}</li>
</ul>`;
$("#alert").dialog({
@ -495,8 +632,8 @@ function showInfo() {
buttons: {
OK: function () {
$(this).dialog("close");
}
},
},
position: {my: "center", at: "center", of: "svg"}
position: { my: "center", at: "center", of: "svg" },
});
}

File diff suppressed because it is too large Load diff