mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 01:41:22 +01:00
v1.0.09
This commit is contained in:
parent
baf23bee37
commit
e743735e57
11 changed files with 789 additions and 546 deletions
|
|
@ -103,21 +103,22 @@
|
|||
// place secondary settlements based on geo and economical evaluation
|
||||
function placeTowns() {
|
||||
console.time('placeTowns');
|
||||
const score = new Int16Array(cells.s.map(s => s * gauss(1,3,0,20,3))); // 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
|
||||
const score = new Int16Array(cells.s.map(s => s * gauss(1,3,0,20,3))); // a bit randomized cell score for towns placement
|
||||
const sorted = cells.i.filter(i => !cells.burg[i] && score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes
|
||||
|
||||
const desiredNumber = manorsInput.value == 1000 ? rn(sorted.length / 8 / densityInput.value ** .8) : manorsInput.valueAsNumber;
|
||||
const burgsNumber = Math.min(desiredNumber, sorted.length);
|
||||
const burgsNumber = Math.min(desiredNumber, sorted.length); // towns to generate
|
||||
let burgsAdded = 0;
|
||||
|
||||
const burgsTree = burgs[0];
|
||||
let spacing = (graphWidth + graphHeight) / 150 / (burgsNumber ** .7 / 66); // min distance between towns
|
||||
|
||||
while (burgsAdded < burgsNumber) {
|
||||
while (burgsAdded < burgsNumber && spacing > 1) {
|
||||
for (let i=0; burgsAdded < burgsNumber && i < sorted.length; i++) {
|
||||
if (cells.burg[sorted[i]]) continue;
|
||||
const cell = sorted[i], x = cells.p[cell][0], y = cells.p[cell][1];
|
||||
const s = spacing * gauss(1, .3, .2, 2, 2); // randomize to make the placement not uniform
|
||||
if (cells.burg[cell] || burgsTree.find(x, y, s) !== undefined) continue; // to close to existing burg
|
||||
const s = spacing * gauss(1, .3, .2, 2, 2); // randomize to make placement not uniform
|
||||
if (burgsTree.find(x, y, s) !== undefined) continue; // to close to existing burg
|
||||
const burg = burgs.length;
|
||||
const culture = cells.culture[cell];
|
||||
const name = Names.getCulture(culture);
|
||||
|
|
@ -133,11 +134,7 @@
|
|||
console.error(`Cannot place all burgs. Requested ${desiredNumber}, placed ${burgsAdded}`);
|
||||
}
|
||||
|
||||
//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)));
|
||||
//labels.selectAll("text").data(sorted).enter().append("text").attr("x", d => cells.p[d][0]).attr("y", d => cells.p[d][1]).text(d => score[d]).attr("font-size", 2);
|
||||
|
||||
burgs[0] = {name:undefined};
|
||||
burgs[0] = {name:undefined}; // do not store burgsTree anymore
|
||||
console.timeEnd('placeTowns');
|
||||
}
|
||||
}
|
||||
|
|
@ -823,7 +820,7 @@
|
|||
cells.province = new Uint16Array(cells.i.length); // cell state
|
||||
const percentage = +provincesInput.value;
|
||||
if (states.length < 2 || !percentage) return; // no provinces
|
||||
const max = gauss(400, 50, 300, 500) / percentage ** .5; // max growth in 300-30 range
|
||||
const max = percentage == 100 ? 1000 : gauss(20, 5, 5, 100) * percentage ** .5; // max growth
|
||||
|
||||
const forms = {
|
||||
Monarchy:{County:11, Earldom:3, Shire:1, Landgrave:1, Margrave:1, Barony:1},
|
||||
|
|
|
|||
|
|
@ -152,8 +152,9 @@ function GFontToDataURI(url) {
|
|||
}
|
||||
|
||||
// prepare map data for saving
|
||||
function getMapURL() {
|
||||
console.time("saveMap");
|
||||
function getMapData() {
|
||||
if (customization) return false;
|
||||
console.time("createMapDataBlob");
|
||||
|
||||
return new Promise(resolve => {
|
||||
const date = new Date();
|
||||
|
|
@ -192,33 +193,33 @@ function getMapURL() {
|
|||
pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl,
|
||||
pack.cells.pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state,
|
||||
pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces].join("\r\n");
|
||||
const dataBlob = new Blob([data], {type: "text/plain"});
|
||||
const URL = window.URL.createObjectURL(dataBlob);
|
||||
|
||||
console.timeEnd("saveMap");
|
||||
resolve(URL);
|
||||
const blob = new Blob([data], {type: "text/plain"});
|
||||
|
||||
console.timeEnd("createMapDataBlob");
|
||||
resolve(blob);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Save in .map format
|
||||
// Download .map file
|
||||
async function saveMap() {
|
||||
if (customization) {tip("Map cannot be saved when is in edit mode, please exit the mode and retry", false, "error"); return;}
|
||||
if (customization) {tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error"); return;}
|
||||
closeDialogs();
|
||||
|
||||
const URL = await getMapURL();
|
||||
const blob = await getMapData();
|
||||
const URL = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "fantasy_map_" + Date.now() + ".map";
|
||||
link.href = URL;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check`, true, "success", 7000);
|
||||
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
||||
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
|
||||
}
|
||||
|
||||
function uploadFile(file, callback) {
|
||||
console.time("loadMap");
|
||||
closeDialogs();
|
||||
uploadFile.timeStart = performance.now();
|
||||
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = function(fileLoadedEvent) {
|
||||
const dataLoaded = fileLoadedEvent.target.result;
|
||||
|
|
@ -252,285 +253,386 @@ function uploadFile(file, callback) {
|
|||
}
|
||||
|
||||
function parseLoadedData(data) {
|
||||
closeDialogs();
|
||||
const reliefIcons = document.getElementById("defs-relief").innerHTML; // save relief icons
|
||||
const hatching = document.getElementById("hatching").cloneNode(true); // save hatching
|
||||
|
||||
void function parseParameters() {
|
||||
const params = data[0].split("|");
|
||||
if (params[3]) {seed = params[3]; optionsSeed.value = seed;}
|
||||
if (params[4]) graphWidth = +params[4];
|
||||
if (params[5]) graphHeight = +params[5];
|
||||
}()
|
||||
|
||||
void function parseOptions() {
|
||||
const options = data[1].split("|");
|
||||
if (options[0]) applyOption(distanceUnitInput, options[0]);
|
||||
if (options[1]) distanceScaleInput.value = distanceScaleOutput.value = options[1];
|
||||
if (options[2]) areaUnit.value = options[2];
|
||||
if (options[3]) applyOption(heightUnit, options[3]);
|
||||
if (options[4]) heightExponentInput.value = heightExponentOutput.value = options[4];
|
||||
if (options[5]) temperatureScale.value = options[5];
|
||||
if (options[6]) barSize.value = barSizeOutput.value = options[6];
|
||||
if (options[7] !== undefined) barLabel.value = options[7];
|
||||
if (options[8] !== undefined) barBackOpacity.value = options[8];
|
||||
if (options[9]) barBackColor.value = options[9];
|
||||
if (options[10]) barPosX.value = options[10];
|
||||
if (options[11]) barPosY.value = options[11];
|
||||
if (options[12]) populationRate.value = populationRateOutput.value = options[12];
|
||||
if (options[13]) urbanization.value = urbanizationOutput.value = options[13];
|
||||
if (options[14]) mapSizeInput.value = mapSizeOutput.value = Math.max(Math.min(options[14], 100), 1);
|
||||
if (options[15]) latitudeInput.value = latitudeOutput.value = Math.max(Math.min(options[15], 100), 0);
|
||||
if (options[16]) temperatureEquatorInput.value = temperatureEquatorOutput.value = options[16];
|
||||
if (options[17]) temperaturePoleInput.value = temperaturePoleOutput.value = options[17];
|
||||
if (options[18]) precInput.value = precOutput.value = options[18];
|
||||
if (options[19]) winds = JSON.parse(options[19]);
|
||||
}()
|
||||
|
||||
void function parseConfiguration() {
|
||||
if (data[2]) mapCoordinates = JSON.parse(data[2]);
|
||||
if (data[4]) notes = JSON.parse(data[4]);
|
||||
|
||||
const biomes = data[3].split("|");
|
||||
biomesData = applyDefaultBiomesSystem();
|
||||
biomesData.color = biomes[0].split(",");
|
||||
biomesData.habitability = biomes[1].split(",").map(h => +h);
|
||||
biomesData.name = biomes[2].split(",");
|
||||
|
||||
// push custom biomes if any
|
||||
for (let i=biomesData.i.length; i < biomesData.name.length; i++) {
|
||||
biomesData.i.push(biomesData.i.length);
|
||||
biomesData.iconsDensity.push(0);
|
||||
biomesData.icons.push([]);
|
||||
biomesData.cost.push(50);
|
||||
}
|
||||
}()
|
||||
|
||||
void function replaceSVG() {
|
||||
svg.remove();
|
||||
document.body.insertAdjacentHTML("afterbegin", data[5]);
|
||||
}()
|
||||
|
||||
void function redefineElements() {
|
||||
svg = d3.select("#map");
|
||||
defs = svg.select("#deftemp");
|
||||
viewbox = svg.select("#viewbox");
|
||||
scaleBar = svg.select("#scaleBar");
|
||||
legend = svg.select("#legend");
|
||||
ocean = viewbox.select("#ocean");
|
||||
oceanLayers = ocean.select("#oceanLayers");
|
||||
oceanPattern = ocean.select("#oceanPattern");
|
||||
lakes = viewbox.select("#lakes");
|
||||
landmass = viewbox.select("#landmass");
|
||||
texture = viewbox.select("#texture");
|
||||
terrs = viewbox.select("#terrs");
|
||||
biomes = viewbox.select("#biomes");
|
||||
cells = viewbox.select("#cells");
|
||||
gridOverlay = viewbox.select("#gridOverlay");
|
||||
coordinates = viewbox.select("#coordinates");
|
||||
compass = viewbox.select("#compass");
|
||||
rivers = viewbox.select("#rivers");
|
||||
terrain = viewbox.select("#terrain");
|
||||
relig = viewbox.select("#relig");
|
||||
cults = viewbox.select("#cults");
|
||||
regions = viewbox.select("#regions");
|
||||
statesBody = regions.select("#statesBody");
|
||||
statesHalo = regions.select("#statesHalo");
|
||||
provs = viewbox.select("#provs");
|
||||
zones = viewbox.select("#zones");
|
||||
borders = viewbox.select("#borders");
|
||||
stateBorders = borders.select("#stateBorders");
|
||||
provinceBorders = borders.select("#provinceBorders");
|
||||
routes = viewbox.select("#routes");
|
||||
roads = routes.select("#roads");
|
||||
trails = routes.select("#trails");
|
||||
searoutes = routes.select("#searoutes");
|
||||
temperature = viewbox.select("#temperature");
|
||||
coastline = viewbox.select("#coastline");
|
||||
prec = viewbox.select("#prec");
|
||||
population = viewbox.select("#population");
|
||||
labels = viewbox.select("#labels");
|
||||
icons = viewbox.select("#icons");
|
||||
burgIcons = icons.select("#burgIcons");
|
||||
anchors = icons.select("#anchors");
|
||||
markers = viewbox.select("#markers");
|
||||
ruler = viewbox.select("#ruler");
|
||||
fogging = viewbox.select("#fogging");
|
||||
debug = viewbox.select("#debug");
|
||||
freshwater = lakes.select("#freshwater");
|
||||
salt = lakes.select("#salt");
|
||||
burgLabels = labels.select("#burgLabels");
|
||||
}()
|
||||
|
||||
void function parseGridData() {
|
||||
grid = JSON.parse(data[6]);
|
||||
calculateVoronoi(grid, grid.points);
|
||||
grid.cells.h = Uint8Array.from(data[7].split(","));
|
||||
grid.cells.prec = Uint8Array.from(data[8].split(","));
|
||||
grid.cells.f = Uint16Array.from(data[9].split(","));
|
||||
grid.cells.t = Int8Array.from(data[10].split(","));
|
||||
grid.cells.temp = Int8Array.from(data[11].split(","));
|
||||
}()
|
||||
|
||||
void function parsePackData() {
|
||||
pack = {};
|
||||
reGraph();
|
||||
reMarkFeatures();
|
||||
pack.features = JSON.parse(data[12]);
|
||||
pack.cultures = JSON.parse(data[13]);
|
||||
pack.states = JSON.parse(data[14]);
|
||||
pack.burgs = JSON.parse(data[15]);
|
||||
pack.religions = data[29] ? JSON.parse(data[29]) : [{i: 0, name: "No religion"}];
|
||||
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
|
||||
|
||||
const cells = pack.cells;
|
||||
cells.biome = Uint8Array.from(data[16].split(","));
|
||||
cells.burg = Uint16Array.from(data[17].split(","));
|
||||
cells.conf = Uint8Array.from(data[18].split(","));
|
||||
cells.culture = Uint16Array.from(data[19].split(","));
|
||||
cells.fl = Uint16Array.from(data[20].split(","));
|
||||
cells.pop = Uint16Array.from(data[21].split(","));
|
||||
cells.r = Uint16Array.from(data[22].split(","));
|
||||
cells.road = Uint16Array.from(data[23].split(","));
|
||||
cells.s = Uint16Array.from(data[24].split(","));
|
||||
cells.state = Uint16Array.from(data[25].split(","));
|
||||
cells.religion = data[26] ? Uint16Array.from(data[26].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.crossroad = data[28] ? Uint16Array.from(data[28].split(",")) : new Uint16Array(cells.i.length);
|
||||
}()
|
||||
|
||||
void function restoreLayersState() {
|
||||
if (texture.style("display") !== "none" && texture.select("image").size()) turnButtonOn("toggleTexture"); else turnButtonOff("toggleTexture");
|
||||
if (terrs.selectAll("*").size()) turnButtonOn("toggleHeight"); else turnButtonOff("toggleHeight");
|
||||
if (biomes.selectAll("*").size()) turnButtonOn("toggleBiomes"); else turnButtonOff("toggleBiomes");
|
||||
if (cells.selectAll("*").size()) turnButtonOn("toggleCells"); else turnButtonOff("toggleCells");
|
||||
if (gridOverlay.selectAll("*").size()) turnButtonOn("toggleGrid"); else turnButtonOff("toggleGrid");
|
||||
if (coordinates.selectAll("*").size()) turnButtonOn("toggleCoordinates"); else turnButtonOff("toggleCoordinates");
|
||||
if (compass.style("display") !== "none" && compass.select("use").size()) turnButtonOn("toggleCompass"); else turnButtonOff("toggleCompass");
|
||||
if (rivers.style("display") !== "none") turnButtonOn("toggleRivers"); else turnButtonOff("toggleRivers");
|
||||
if (terrain.style("display") !== "none" && terrain.selectAll("*").size()) turnButtonOn("toggleRelief"); else turnButtonOff("toggleRelief");
|
||||
if (relig.selectAll("*").size()) turnButtonOn("toggleReligions"); else turnButtonOff("toggleReligions");
|
||||
if (cults.selectAll("*").size()) turnButtonOn("toggleCultures"); else turnButtonOff("toggleCultures");
|
||||
if (statesBody.selectAll("*").size()) turnButtonOn("toggleStates"); else turnButtonOff("toggleStates");
|
||||
if (provs.selectAll("*").size()) turnButtonOn("toggleProvinces"); else turnButtonOff("toggleProvinces");
|
||||
if (zones.selectAll("*").size() && zones.style("display") !== "none") turnButtonOn("toggleZones"); else turnButtonOff("toggleZones");
|
||||
if (borders.style("display") !== "none") turnButtonOn("toggleBorders"); else turnButtonOff("toggleBorders");
|
||||
if (routes.style("display") !== "none" && routes.selectAll("path").size()) turnButtonOn("toggleRoutes"); else turnButtonOff("toggleRoutes");
|
||||
if (temperature.selectAll("*").size()) turnButtonOn("toggleTemp"); else turnButtonOff("toggleTemp");
|
||||
if (prec.selectAll("circle").size()) turnButtonOn("togglePrec"); else turnButtonOff("togglePrec");
|
||||
if (labels.style("display") !== "none") turnButtonOn("toggleLabels"); else turnButtonOff("toggleLabels");
|
||||
if (icons.style("display") !== "none") turnButtonOn("toggleIcons"); else turnButtonOff("toggleIcons");
|
||||
if (markers.selectAll("*").size() && markers.style("display") !== "none") turnButtonOn("toggleMarkers"); else turnButtonOff("toggleMarkers");
|
||||
if (ruler.style("display") !== "none") turnButtonOn("toggleRulers"); else turnButtonOff("toggleRulers");
|
||||
if (scaleBar.style("display") !== "none") turnButtonOn("toggleScaleBar"); else turnButtonOff("toggleScaleBar");
|
||||
|
||||
// special case for population bars
|
||||
const populationIsOn = population.selectAll("line").size();
|
||||
if (populationIsOn) drawPopulation();
|
||||
if (populationIsOn) turnButtonOn("togglePopulation"); else turnButtonOff("togglePopulation");
|
||||
|
||||
getCurrentPreset();
|
||||
}()
|
||||
|
||||
void function restoreEvents() {
|
||||
ruler.selectAll("g").call(d3.drag().on("start", dragRuler));
|
||||
ruler.selectAll("text").on("click", removeParent);
|
||||
ruler.selectAll("g.ruler circle").call(d3.drag().on("drag", dragRulerEdge));
|
||||
ruler.selectAll("g.ruler circle").call(d3.drag().on("drag", dragRulerEdge));
|
||||
ruler.selectAll("g.ruler rect").call(d3.drag().on("start", rulerCenterDrag));
|
||||
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
|
||||
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
|
||||
|
||||
scaleBar.on("mousemove", () => tip("Click to open Units Editor"));
|
||||
legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend());
|
||||
}()
|
||||
|
||||
void function resolveVersionConflicts() {
|
||||
const version = parseFloat(data[0].split("|")[0]);
|
||||
if (version == 0.8) {
|
||||
// 0.9 has additional relief icons to be included into older maps
|
||||
document.getElementById("defs-relief").innerHTML = reliefIcons;
|
||||
}
|
||||
|
||||
if (version < 1) {
|
||||
// 1.0 adds a new religions layer
|
||||
relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
||||
Religions.generate();
|
||||
|
||||
// 1.0 adds a legend box
|
||||
legend = svg.append("g").attr("id", "legend");
|
||||
legend.attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC")
|
||||
.attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93)
|
||||
.attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
|
||||
|
||||
// 1.0 separated drawBorders fron drawStates()
|
||||
stateBorders = borders.append("g").attr("id", "stateBorders");
|
||||
provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
||||
borders.attr("opacity", null).attr("stroke", null).attr("stroke-width", null).attr("stroke-dasharray", null).attr("stroke-linecap", null).attr("filter", null);
|
||||
stateBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
|
||||
provinceBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
|
||||
|
||||
// 1.0 adds state relations, provinces, forms and full names
|
||||
provs = viewbox.insert("g", "#borders").attr("id", "provs").attr("opacity", .6);
|
||||
BurgsAndStates.collectStatistics();
|
||||
BurgsAndStates.generateDiplomacy();
|
||||
BurgsAndStates.defineStateForms();
|
||||
drawStates();
|
||||
BurgsAndStates.generateProvinces();
|
||||
drawBorders();
|
||||
if (!layerIsOn("toggleBorders")) $('#borders').fadeOut();
|
||||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
||||
|
||||
// 1.0 adds hatching
|
||||
document.getElementsByTagName("defs")[0].appendChild(hatching);
|
||||
|
||||
// 1.0 adds zones layer
|
||||
zones = viewbox.insert("g", "#borders").attr("id", "zones").attr("display", "none");
|
||||
zones.attr("opacity", .6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt");
|
||||
addZone();
|
||||
if (!markers.selectAll("*").size()) {addMarkers(); turnButtonOn("toggleMarkers");}
|
||||
|
||||
// 1.0 add fogging layer (state focus)
|
||||
let fogging = viewbox.insert("g", "#ruler").attr("id", "fogging-cont").attr("mask", "url(#fog)")
|
||||
.append("g").attr("id", "fogging").attr("display", "none");
|
||||
fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%");
|
||||
defs.append("mask").attr("id", "fog").append("rect").attr("x", 0).attr("y", 0).attr("width", "100%")
|
||||
.attr("height", "100%").attr("fill", "white");
|
||||
|
||||
// 1.0 changes states opacity bask to regions level
|
||||
if (statesBody.attr("opacity")) {
|
||||
regions.attr("opacity", statesBody.attr("opacity"));
|
||||
statesBody.attr("opacity", null);
|
||||
try {
|
||||
const reliefIcons = document.getElementById("defs-relief").innerHTML; // save relief icons
|
||||
const hatching = document.getElementById("hatching").cloneNode(true); // save hatching
|
||||
|
||||
void function parseParameters() {
|
||||
const params = data[0].split("|");
|
||||
if (params[3]) {seed = params[3]; optionsSeed.value = seed;}
|
||||
if (params[4]) graphWidth = +params[4];
|
||||
if (params[5]) graphHeight = +params[5];
|
||||
}()
|
||||
|
||||
console.group("Loaded Map " + seed);
|
||||
|
||||
void function parseOptions() {
|
||||
const options = data[1].split("|");
|
||||
if (options[0]) applyOption(distanceUnitInput, options[0]);
|
||||
if (options[1]) distanceScaleInput.value = distanceScaleOutput.value = options[1];
|
||||
if (options[2]) areaUnit.value = options[2];
|
||||
if (options[3]) applyOption(heightUnit, options[3]);
|
||||
if (options[4]) heightExponentInput.value = heightExponentOutput.value = options[4];
|
||||
if (options[5]) temperatureScale.value = options[5];
|
||||
if (options[6]) barSize.value = barSizeOutput.value = options[6];
|
||||
if (options[7] !== undefined) barLabel.value = options[7];
|
||||
if (options[8] !== undefined) barBackOpacity.value = options[8];
|
||||
if (options[9]) barBackColor.value = options[9];
|
||||
if (options[10]) barPosX.value = options[10];
|
||||
if (options[11]) barPosY.value = options[11];
|
||||
if (options[12]) populationRate.value = populationRateOutput.value = options[12];
|
||||
if (options[13]) urbanization.value = urbanizationOutput.value = options[13];
|
||||
if (options[14]) mapSizeInput.value = mapSizeOutput.value = Math.max(Math.min(options[14], 100), 1);
|
||||
if (options[15]) latitudeInput.value = latitudeOutput.value = Math.max(Math.min(options[15], 100), 0);
|
||||
if (options[16]) temperatureEquatorInput.value = temperatureEquatorOutput.value = options[16];
|
||||
if (options[17]) temperaturePoleInput.value = temperaturePoleOutput.value = options[17];
|
||||
if (options[18]) precInput.value = precOutput.value = options[18];
|
||||
if (options[19]) winds = JSON.parse(options[19]);
|
||||
}()
|
||||
|
||||
void function parseConfiguration() {
|
||||
if (data[2]) mapCoordinates = JSON.parse(data[2]);
|
||||
if (data[4]) notes = JSON.parse(data[4]);
|
||||
|
||||
const biomes = data[3].split("|");
|
||||
biomesData = applyDefaultBiomesSystem();
|
||||
biomesData.color = biomes[0].split(",");
|
||||
biomesData.habitability = biomes[1].split(",").map(h => +h);
|
||||
biomesData.name = biomes[2].split(",");
|
||||
|
||||
// push custom biomes if any
|
||||
for (let i=biomesData.i.length; i < biomesData.name.length; i++) {
|
||||
biomesData.i.push(biomesData.i.length);
|
||||
biomesData.iconsDensity.push(0);
|
||||
biomesData.icons.push([]);
|
||||
biomesData.cost.push(50);
|
||||
}
|
||||
|
||||
// 1.0 changed labels to multi-lined
|
||||
labels.selectAll("textPath").each(function() {
|
||||
const text = this.textContent;
|
||||
const shift = this.getComputedTextLength() / -1.5;
|
||||
this.innerHTML = `<tspan x="${shift}">${text}</tspan>`;
|
||||
});
|
||||
|
||||
// 1.0 added new biome - Wetland
|
||||
biomesData.name.push("Wetland");
|
||||
biomesData.color.push("#0b9131");
|
||||
biomesData.habitability.push(12);
|
||||
}
|
||||
|
||||
if (version == 1) {
|
||||
// v 1.0 initial code had a bug with religion layer id
|
||||
if (!relig.size()) relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
||||
|
||||
// v 1.0 initially has Sympathy status then relaced with Friendly
|
||||
for (const s of pack.states) {
|
||||
s.diplomacy = s.diplomacy.map(r => r === "Sympathy" ? "Friendly" : r);
|
||||
}()
|
||||
|
||||
void function replaceSVG() {
|
||||
svg.remove();
|
||||
document.body.insertAdjacentHTML("afterbegin", data[5]);
|
||||
}()
|
||||
|
||||
void function redefineElements() {
|
||||
svg = d3.select("#map");
|
||||
defs = svg.select("#deftemp");
|
||||
viewbox = svg.select("#viewbox");
|
||||
scaleBar = svg.select("#scaleBar");
|
||||
legend = svg.select("#legend");
|
||||
ocean = viewbox.select("#ocean");
|
||||
oceanLayers = ocean.select("#oceanLayers");
|
||||
oceanPattern = ocean.select("#oceanPattern");
|
||||
lakes = viewbox.select("#lakes");
|
||||
landmass = viewbox.select("#landmass");
|
||||
texture = viewbox.select("#texture");
|
||||
terrs = viewbox.select("#terrs");
|
||||
biomes = viewbox.select("#biomes");
|
||||
cells = viewbox.select("#cells");
|
||||
gridOverlay = viewbox.select("#gridOverlay");
|
||||
coordinates = viewbox.select("#coordinates");
|
||||
compass = viewbox.select("#compass");
|
||||
rivers = viewbox.select("#rivers");
|
||||
terrain = viewbox.select("#terrain");
|
||||
relig = viewbox.select("#relig");
|
||||
cults = viewbox.select("#cults");
|
||||
regions = viewbox.select("#regions");
|
||||
statesBody = regions.select("#statesBody");
|
||||
statesHalo = regions.select("#statesHalo");
|
||||
provs = viewbox.select("#provs");
|
||||
zones = viewbox.select("#zones");
|
||||
borders = viewbox.select("#borders");
|
||||
stateBorders = borders.select("#stateBorders");
|
||||
provinceBorders = borders.select("#provinceBorders");
|
||||
routes = viewbox.select("#routes");
|
||||
roads = routes.select("#roads");
|
||||
trails = routes.select("#trails");
|
||||
searoutes = routes.select("#searoutes");
|
||||
temperature = viewbox.select("#temperature");
|
||||
coastline = viewbox.select("#coastline");
|
||||
prec = viewbox.select("#prec");
|
||||
population = viewbox.select("#population");
|
||||
labels = viewbox.select("#labels");
|
||||
icons = viewbox.select("#icons");
|
||||
burgIcons = icons.select("#burgIcons");
|
||||
anchors = icons.select("#anchors");
|
||||
markers = viewbox.select("#markers");
|
||||
ruler = viewbox.select("#ruler");
|
||||
fogging = viewbox.select("#fogging");
|
||||
debug = viewbox.select("#debug");
|
||||
freshwater = lakes.select("#freshwater");
|
||||
salt = lakes.select("#salt");
|
||||
burgLabels = labels.select("#burgLabels");
|
||||
}()
|
||||
|
||||
void function parseGridData() {
|
||||
grid = JSON.parse(data[6]);
|
||||
calculateVoronoi(grid, grid.points);
|
||||
grid.cells.h = Uint8Array.from(data[7].split(","));
|
||||
grid.cells.prec = Uint8Array.from(data[8].split(","));
|
||||
grid.cells.f = Uint16Array.from(data[9].split(","));
|
||||
grid.cells.t = Int8Array.from(data[10].split(","));
|
||||
grid.cells.temp = Int8Array.from(data[11].split(","));
|
||||
}()
|
||||
|
||||
void function parsePackData() {
|
||||
pack = {};
|
||||
reGraph();
|
||||
reMarkFeatures();
|
||||
pack.features = JSON.parse(data[12]);
|
||||
pack.cultures = JSON.parse(data[13]);
|
||||
pack.states = JSON.parse(data[14]);
|
||||
pack.burgs = JSON.parse(data[15]);
|
||||
pack.religions = data[29] ? JSON.parse(data[29]) : [{i: 0, name: "No religion"}];
|
||||
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
|
||||
|
||||
const cells = pack.cells;
|
||||
cells.biome = Uint8Array.from(data[16].split(","));
|
||||
cells.burg = Uint16Array.from(data[17].split(","));
|
||||
cells.conf = Uint8Array.from(data[18].split(","));
|
||||
cells.culture = Uint16Array.from(data[19].split(","));
|
||||
cells.fl = Uint16Array.from(data[20].split(","));
|
||||
cells.pop = Uint16Array.from(data[21].split(","));
|
||||
cells.r = Uint16Array.from(data[22].split(","));
|
||||
cells.road = Uint16Array.from(data[23].split(","));
|
||||
cells.s = Uint16Array.from(data[24].split(","));
|
||||
cells.state = Uint16Array.from(data[25].split(","));
|
||||
cells.religion = data[26] ? Uint16Array.from(data[26].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.crossroad = data[28] ? Uint16Array.from(data[28].split(",")) : new Uint16Array(cells.i.length);
|
||||
}()
|
||||
|
||||
void function restoreLayersState() {
|
||||
if (texture.style("display") !== "none" && texture.select("image").size()) turnButtonOn("toggleTexture"); else turnButtonOff("toggleTexture");
|
||||
if (terrs.selectAll("*").size()) turnButtonOn("toggleHeight"); else turnButtonOff("toggleHeight");
|
||||
if (biomes.selectAll("*").size()) turnButtonOn("toggleBiomes"); else turnButtonOff("toggleBiomes");
|
||||
if (cells.selectAll("*").size()) turnButtonOn("toggleCells"); else turnButtonOff("toggleCells");
|
||||
if (gridOverlay.selectAll("*").size()) turnButtonOn("toggleGrid"); else turnButtonOff("toggleGrid");
|
||||
if (coordinates.selectAll("*").size()) turnButtonOn("toggleCoordinates"); else turnButtonOff("toggleCoordinates");
|
||||
if (compass.style("display") !== "none" && compass.select("use").size()) turnButtonOn("toggleCompass"); else turnButtonOff("toggleCompass");
|
||||
if (rivers.style("display") !== "none") turnButtonOn("toggleRivers"); else turnButtonOff("toggleRivers");
|
||||
if (terrain.style("display") !== "none" && terrain.selectAll("*").size()) turnButtonOn("toggleRelief"); else turnButtonOff("toggleRelief");
|
||||
if (relig.selectAll("*").size()) turnButtonOn("toggleReligions"); else turnButtonOff("toggleReligions");
|
||||
if (cults.selectAll("*").size()) turnButtonOn("toggleCultures"); else turnButtonOff("toggleCultures");
|
||||
if (statesBody.selectAll("*").size()) turnButtonOn("toggleStates"); else turnButtonOff("toggleStates");
|
||||
if (provs.selectAll("*").size()) turnButtonOn("toggleProvinces"); else turnButtonOff("toggleProvinces");
|
||||
if (zones.selectAll("*").size() && zones.style("display") !== "none") turnButtonOn("toggleZones"); else turnButtonOff("toggleZones");
|
||||
if (borders.style("display") !== "none") turnButtonOn("toggleBorders"); else turnButtonOff("toggleBorders");
|
||||
if (routes.style("display") !== "none" && routes.selectAll("path").size()) turnButtonOn("toggleRoutes"); else turnButtonOff("toggleRoutes");
|
||||
if (temperature.selectAll("*").size()) turnButtonOn("toggleTemp"); else turnButtonOff("toggleTemp");
|
||||
if (prec.selectAll("circle").size()) turnButtonOn("togglePrec"); else turnButtonOff("togglePrec");
|
||||
if (labels.style("display") !== "none") turnButtonOn("toggleLabels"); else turnButtonOff("toggleLabels");
|
||||
if (icons.style("display") !== "none") turnButtonOn("toggleIcons"); else turnButtonOff("toggleIcons");
|
||||
if (markers.selectAll("*").size() && markers.style("display") !== "none") turnButtonOn("toggleMarkers"); else turnButtonOff("toggleMarkers");
|
||||
if (ruler.style("display") !== "none") turnButtonOn("toggleRulers"); else turnButtonOff("toggleRulers");
|
||||
if (scaleBar.style("display") !== "none") turnButtonOn("toggleScaleBar"); else turnButtonOff("toggleScaleBar");
|
||||
|
||||
// special case for population bars
|
||||
const populationIsOn = population.selectAll("line").size();
|
||||
if (populationIsOn) drawPopulation();
|
||||
if (populationIsOn) turnButtonOn("togglePopulation"); else turnButtonOff("togglePopulation");
|
||||
|
||||
getCurrentPreset();
|
||||
}()
|
||||
|
||||
void function restoreEvents() {
|
||||
ruler.selectAll("g").call(d3.drag().on("start", dragRuler));
|
||||
ruler.selectAll("text").on("click", removeParent);
|
||||
ruler.selectAll("g.ruler circle").call(d3.drag().on("drag", dragRulerEdge));
|
||||
ruler.selectAll("g.ruler circle").call(d3.drag().on("drag", dragRulerEdge));
|
||||
ruler.selectAll("g.ruler rect").call(d3.drag().on("start", rulerCenterDrag));
|
||||
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
|
||||
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
|
||||
|
||||
scaleBar.on("mousemove", () => tip("Click to open Units Editor"));
|
||||
legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend());
|
||||
}()
|
||||
|
||||
void function resolveVersionConflicts() {
|
||||
const version = parseFloat(data[0].split("|")[0]);
|
||||
if (version == 0.8) {
|
||||
// 0.9 has additional relief icons to be included into older maps
|
||||
document.getElementById("defs-relief").innerHTML = reliefIcons;
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if (version < 1) {
|
||||
// 1.0 adds a new religions layer
|
||||
relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
||||
Religions.generate();
|
||||
|
||||
// 1.0 adds a legend box
|
||||
legend = svg.append("g").attr("id", "legend");
|
||||
legend.attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC")
|
||||
.attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93)
|
||||
.attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
|
||||
|
||||
// 1.0 separated drawBorders fron drawStates()
|
||||
stateBorders = borders.append("g").attr("id", "stateBorders");
|
||||
provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
||||
borders.attr("opacity", null).attr("stroke", null).attr("stroke-width", null).attr("stroke-dasharray", null).attr("stroke-linecap", null).attr("filter", null);
|
||||
stateBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
|
||||
provinceBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
|
||||
|
||||
// 1.0 adds state relations, provinces, forms and full names
|
||||
provs = viewbox.insert("g", "#borders").attr("id", "provs").attr("opacity", .6);
|
||||
BurgsAndStates.collectStatistics();
|
||||
BurgsAndStates.generateDiplomacy();
|
||||
BurgsAndStates.defineStateForms();
|
||||
drawStates();
|
||||
BurgsAndStates.generateProvinces();
|
||||
drawBorders();
|
||||
if (!layerIsOn("toggleBorders")) $('#borders').fadeOut();
|
||||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
||||
|
||||
// 1.0 adds hatching
|
||||
document.getElementsByTagName("defs")[0].appendChild(hatching);
|
||||
|
||||
// 1.0 adds zones layer
|
||||
zones = viewbox.insert("g", "#borders").attr("id", "zones").attr("display", "none");
|
||||
zones.attr("opacity", .6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt");
|
||||
addZone();
|
||||
if (!markers.selectAll("*").size()) {addMarkers(); turnButtonOn("toggleMarkers");}
|
||||
|
||||
// 1.0 add fogging layer (state focus)
|
||||
let fogging = viewbox.insert("g", "#ruler").attr("id", "fogging-cont").attr("mask", "url(#fog)")
|
||||
.append("g").attr("id", "fogging").attr("display", "none");
|
||||
fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%");
|
||||
defs.append("mask").attr("id", "fog").append("rect").attr("x", 0).attr("y", 0).attr("width", "100%")
|
||||
.attr("height", "100%").attr("fill", "white");
|
||||
|
||||
// 1.0 changes states opacity bask to regions level
|
||||
if (statesBody.attr("opacity")) {
|
||||
regions.attr("opacity", statesBody.attr("opacity"));
|
||||
statesBody.attr("opacity", null);
|
||||
}
|
||||
|
||||
// 1.0 changed labels to multi-lined
|
||||
labels.selectAll("textPath").each(function() {
|
||||
const text = this.textContent;
|
||||
const shift = this.getComputedTextLength() / -1.5;
|
||||
this.innerHTML = `<tspan x="${shift}">${text}</tspan>`;
|
||||
});
|
||||
|
||||
// 1.0 added new biome - Wetland
|
||||
biomesData.name.push("Wetland");
|
||||
biomesData.color.push("#0b9131");
|
||||
biomesData.habitability.push(12);
|
||||
}
|
||||
|
||||
if (version == 1) {
|
||||
// v 1.0 initial code had a bug with religion layer id
|
||||
if (!relig.size()) relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
||||
|
||||
// v 1.0 initially has Sympathy status then relaced with Friendly
|
||||
for (const s of pack.states) {
|
||||
s.diplomacy = s.diplomacy.map(r => r === "Sympathy" ? "Friendly" : r);
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
changeMapSize();
|
||||
if (window.restoreDefaultEvents) restoreDefaultEvents();
|
||||
invokeActiveZooming();
|
||||
|
||||
console.warn(`TOTAL: ${rn((performance.now()-uploadFile.timeStart)/1000,2)}s`);
|
||||
showStatistics();
|
||||
console.groupEnd("Loaded Map " + seed);
|
||||
tip("Map is successfully loaded", true, "success", 7000);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
clearMainTip();
|
||||
|
||||
const regex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
|
||||
const errorNoURL = error.stack.replace(regex, url => '<i>' + last(url.split("/")) + '</i>');
|
||||
const errorParsed = errorNoURL.replace(/ at /ig, "<br> at ");
|
||||
|
||||
alertMessage.innerHTML = `An error is occured on map loading. Select a different file to load,
|
||||
<br>generate a new random map or cancel the loading
|
||||
<p id="errorBox">${errorParsed}</p>`;
|
||||
$("#alert").dialog({
|
||||
resizable: false, title: "Loading error", maxWidth:500, buttons: {
|
||||
"Select file": function() {$(this).dialog("close"); mapToLoad.click();},
|
||||
"New map": function() {$(this).dialog("close"); regenerateMap();},
|
||||
Cancel: function() {$(this).dialog("close")}
|
||||
}, position: {my: "center", at: "center", of: "svg"}
|
||||
});
|
||||
}
|
||||
|
||||
changeMapSize();
|
||||
restoreDefaultEvents();
|
||||
invokeActiveZooming();
|
||||
tip("Map is successfully loaded", true, "success", 7000);
|
||||
console.timeEnd("loadMap");
|
||||
showStatistics();
|
||||
}
|
||||
|
||||
async function quickSave() {
|
||||
const blob = await getMapData();
|
||||
if (blob) ldb.set("lastMap", blob); // auto-save map
|
||||
tip("Map is saved to browser memory", true, "success", 2000);
|
||||
}
|
||||
|
||||
function quickLoad() {
|
||||
ldb.get("lastMap", blob => {
|
||||
if (blob) {
|
||||
loadMapPrompt(blob);
|
||||
} else {
|
||||
tip("No map stored. Save map to storage first", true, "error", 2000);
|
||||
console.error("No map stored");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadMapPrompt(blob) {
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 10) {loadLastSavedMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to load saved map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({resizable: false, title: "Load saved map",
|
||||
buttons: {
|
||||
Cancel: function() {$(this).dialog("close");},
|
||||
Load: function() {loadLastSavedMap(); $(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
|
||||
function loadLastSavedMap() {
|
||||
console.warn("Load last saved map");
|
||||
closeDialogs();
|
||||
try {
|
||||
uploadFile(blob);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
tip("Cannot load last saved map", true, "error", 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const saveReminder = function() {
|
||||
if (localStorage.getItem("noReminder")) return;
|
||||
const message = ["Please don't forget to save your work as a .map file",
|
||||
"Please remember to save work as a .map file",
|
||||
"Saving in .map format will ensure your data won't be lost in case of issues",
|
||||
"Safety is number one priority. Please save the map",
|
||||
"Don't forget to save your map on a regular basis!",
|
||||
"Just a gentle reminder for you to save the map",
|
||||
"Please 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"];
|
||||
|
||||
saveReminder.reminder = setInterval(() => {
|
||||
if (customization) return;
|
||||
tip(ra(message), true, "warn", 2500);
|
||||
}, 1e6);
|
||||
saveReminder.status = 1;
|
||||
}
|
||||
|
||||
saveReminder();
|
||||
|
||||
function toggleSaveReminder() {
|
||||
if (saveReminder.status) {
|
||||
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);
|
||||
localStorage.removeItem("noReminder");
|
||||
saveReminder();
|
||||
}
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ function editBurgs() {
|
|||
function changeBurgPopulation() {
|
||||
const burg = +this.parentNode.dataset.id;
|
||||
if (this.value == "" || isNaN(+this.value)) {
|
||||
tip("Please provide an integer number", false, "error");
|
||||
tip("Please provide an integer number (like 10000, not 10K)", false, "error");
|
||||
this.value = si(pack.burgs[burg].population * populationRate.value * urbanization.value);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,22 +187,43 @@ function editDiplomacy() {
|
|||
const chronicle = pack.states[0].diplomacy;
|
||||
if (!chronicle.length) {tip("Relations history is blank", false, "error"); return;}
|
||||
|
||||
let message = `<div>`;
|
||||
chronicle.forEach(e => {
|
||||
message += `<div style="margin: 0.5em 0">`;
|
||||
e.forEach((l, i) => message += `<div${i ? "" : " style='font-weight:bold'"}>${l}</div>`);
|
||||
message += `</div>`;
|
||||
let message = `<div autocorrect="off" spellcheck="false">`;
|
||||
chronicle.forEach((e, d) => {
|
||||
message += `<div>`;
|
||||
e.forEach((l, i) => message += `<div contenteditable="true" data-id="${d}-${i}"${i ? "" : " style='font-weight:bold'"}>${l}</div>`);
|
||||
message += `‍</div>`;
|
||||
});
|
||||
alertMessage.innerHTML = message + `</div>`;
|
||||
alertMessage.innerHTML = message + `</div><i id="info-line">Type to edit. Press Enter to add a new line, empty the element to remove it</i>`;
|
||||
alertMessage.querySelectorAll("div[contenteditable='true']").forEach(el => el.addEventListener("input", changeReliationsHistory));
|
||||
|
||||
$("#alert").dialog({title: "Relations history", position: {my: "center", at: "center", of: "svg"},
|
||||
buttons: {
|
||||
Save: function() {
|
||||
const text = this.querySelector("div").innerText.split("\n").join("\r\n");
|
||||
const dataBlob = new Blob([text], {type: "text/plain"});
|
||||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "state_relations_history" + Date.now() + ".txt";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
},
|
||||
Clear: function() {pack.states[0].diplomacy = []; $(this).dialog("close");},
|
||||
Close: function() {$(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeReliationsHistory() {
|
||||
const i = this.dataset.id.split("-");
|
||||
const group = pack.states[0].diplomacy[i[0]];
|
||||
if (this.innerHTML === "") {
|
||||
group.splice(i[1], 1);
|
||||
this.remove();
|
||||
} else group[i[1]] = this.innerHTML;
|
||||
}
|
||||
|
||||
function showRelationsMatrix() {
|
||||
const states = pack.states.filter(s => s.i && !s.removed);
|
||||
const valid = states.map(s => s.i);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
// Module to store general UI functions
|
||||
"use strict";
|
||||
|
||||
// ask before closing the window
|
||||
window.onbeforeunload = () => "Are you sure you want to navigate away?";
|
||||
|
||||
// fit full-screen map if window is resized
|
||||
$(window).resize(function(e) {
|
||||
mapWidthInput.value = window.innerWidth;
|
||||
|
|
@ -11,6 +8,8 @@ $(window).resize(function(e) {
|
|||
changeMapSize();
|
||||
});
|
||||
|
||||
window.onbeforeunload = () => "Are you sure you want to navigate away?";
|
||||
|
||||
// Tooltips
|
||||
const tooltip = document.getElementById("tooltip");
|
||||
|
||||
|
|
@ -230,16 +229,22 @@ function applyOption(select, option) {
|
|||
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
|
||||
document.addEventListener("keydown", function(event) {
|
||||
const active = document.activeElement.tagName;
|
||||
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
|
||||
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
|
||||
if (active === "DIV" && document.activeElement.contentEditable === "true") return; // don't trigger if user inputs a text
|
||||
const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey;
|
||||
if (key === 118) regeneratePrompt(); // "F7" for new map
|
||||
else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||
if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||
else if (key === 9) {toggleOptions(event); event.preventDefault();} // Tab to toggle options
|
||||
|
||||
else if (key === 113) regeneratePrompt(); // "F2" for new map
|
||||
else if (key === 117) quickSave(); // "F6" for quick save
|
||||
else if (key === 120) quickLoad(); // "F9" for quick load
|
||||
|
||||
else if (ctrl && key === 80) saveAsImage("png"); // Ctrl + "P" to save as PNG
|
||||
else if (ctrl && key === 83) saveAsImage("svg"); // Ctrl + "S" to save as SVG
|
||||
else if (ctrl && key === 77) saveMap(); // Ctrl + "M" to save MAP file
|
||||
else if (ctrl && key === 85) mapToLoad.click(); // Ctrl + "U" to load MAP from URL
|
||||
else if (ctrl && key === 76) mapToLoad.click(); // Ctrl + "L" to load MAP from local file
|
||||
else if (ctrl && key === 81) toggleSaveReminder(); // Ctrl + "Q" to toggle save reminder
|
||||
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
|
||||
|
||||
else if (shift && key === 192) console.log(pack.cells); // Shift + "`" to log cells data
|
||||
|
|
|
|||
|
|
@ -22,22 +22,25 @@ function restoreLayers() {
|
|||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
||||
}
|
||||
|
||||
// layers to be turned on; changable by user
|
||||
let presets = {
|
||||
"political": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar", "toggleStates"],
|
||||
"cultural": ["toggleBorders", "toggleCultures", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"religions": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleReligions", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"provinces": ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar"],
|
||||
"biomes": ["toggleBiomes", "toggleRivers", "toggleScaleBar"],
|
||||
"heightmap": ["toggleHeight", "toggleRivers", "toggleScaleBar"],
|
||||
"poi": ["toggleBorders", "toggleHeight", "toggleIcons", "toggleMarkers", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"landmass": ["toggleScaleBar"]
|
||||
}
|
||||
|
||||
restoreLayers(); // run on-load
|
||||
let presets = {}; // global object
|
||||
restoreCustomPresets(); // run on-load
|
||||
|
||||
function getDefaultPresets() {
|
||||
return {
|
||||
"political": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar", "toggleStates"],
|
||||
"cultural": ["toggleBorders", "toggleCultures", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"religions": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleReligions", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"provinces": ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar"],
|
||||
"biomes": ["toggleBiomes", "toggleRivers", "toggleScaleBar"],
|
||||
"heightmap": ["toggleHeight", "toggleRivers", "toggleScaleBar"],
|
||||
"poi": ["toggleBorders", "toggleHeight", "toggleIcons", "toggleMarkers", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"landmass": ["toggleScaleBar"]
|
||||
}
|
||||
}
|
||||
|
||||
function restoreCustomPresets() {
|
||||
presets = getDefaultPresets();
|
||||
const storedPresets = JSON.parse(localStorage.getItem("presets"));
|
||||
if (!storedPresets) return;
|
||||
|
||||
|
|
@ -45,6 +48,7 @@ function restoreCustomPresets() {
|
|||
if (presets[preset]) continue;
|
||||
layersPreset.add(new Option(preset, preset));
|
||||
}
|
||||
|
||||
presets = storedPresets;
|
||||
}
|
||||
|
||||
|
|
@ -62,34 +66,50 @@ function changePreset(preset) {
|
|||
});
|
||||
layersPreset.value = preset;
|
||||
localStorage.setItem("preset", preset);
|
||||
|
||||
const isDefault = getDefaultPresets()[preset];
|
||||
removePresetButton.style.display = isDefault ? "none" : "inline-block";
|
||||
savePresetButton.style.display = "none";
|
||||
}
|
||||
|
||||
function savePreset() {
|
||||
// don't allow if layers should already esist as a preset
|
||||
if (layersPreset.value !== "custom") {
|
||||
tip(`Current layers are already saved as a "${layersPreset.selectedOptions[0].label}" preset`, false, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// add new preset
|
||||
const preset = prompt("Please provide a preset name"); // preset name
|
||||
if (!preset) return;
|
||||
presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
|
||||
layersPreset.add(new Option(preset, preset, false, true));
|
||||
localStorage.setItem("presets", JSON.stringify(presets));
|
||||
localStorage.setItem("preset", preset);
|
||||
removePresetButton.style.display = "inline-block";
|
||||
savePresetButton.style.display = "none";
|
||||
}
|
||||
|
||||
function removePreset() {
|
||||
const preset = layersPreset.value;
|
||||
delete presets[preset];
|
||||
const index = Array.from(layersPreset.options).findIndex(o => o.value === preset);
|
||||
layersPreset.options.remove(index);
|
||||
layersPreset.value = "custom";
|
||||
removePresetButton.style.display = "none";
|
||||
savePresetButton.style.display = "inline-block";
|
||||
|
||||
localStorage.setItem("presets", JSON.stringify(presets));
|
||||
localStorage.removeItem("preset");
|
||||
}
|
||||
|
||||
function getCurrentPreset() {
|
||||
const layers = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
|
||||
const defaultPresets = getDefaultPresets();
|
||||
|
||||
for (const preset in presets) {
|
||||
if (JSON.stringify(presets[preset]) !== JSON.stringify(layers)) continue;
|
||||
layersPreset.value = preset;
|
||||
removePresetButton.style.display = defaultPresets[preset] ? "none" : "inline-block";
|
||||
return;
|
||||
}
|
||||
|
||||
layersPreset.value = "custom";
|
||||
removePresetButton.style.display = "none";
|
||||
savePresetButton.style.display = "inline-block";
|
||||
}
|
||||
|
||||
function toggleHeight() {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,6 @@
|
|||
$("#optionsContainer").draggable({handle: ".drag-trigger", snap: "svg", snapMode: "both"});
|
||||
$("#mapLayers").disableSelection();
|
||||
|
||||
// show control elements and remove loading screen on map load
|
||||
d3.select("#loading").transition().duration(5000).style("opacity", 0).remove();
|
||||
d3.select("#initial").transition().duration(5000).attr("opacity", 0).remove();
|
||||
d3.select("#optionsContainer").transition().duration(5000).style("opacity", 1);
|
||||
d3.select("#tooltip").transition().duration(5000).style("opacity", 1);
|
||||
|
||||
// remove glow if tip is aknowledged
|
||||
if (localStorage.getItem("disable_click_arrow_tooltip")) {
|
||||
clearMainTip();
|
||||
|
|
@ -723,7 +717,7 @@ function changeMapSize() {
|
|||
oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||
oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||
fitScaleBar();
|
||||
fitLegendBox();
|
||||
if (window.fitLegendBox) fitLegendBox();
|
||||
}
|
||||
|
||||
// just apply map size that was already set, apply graph size!
|
||||
|
|
@ -994,28 +988,29 @@ document.getElementById("sticked").addEventListener("click", function(event) {
|
|||
else if (id === "saveButton") toggleSavePane();
|
||||
else if (id === "loadButton") toggleLoadPane();
|
||||
else if (id === "zoomReset") resetZoom(1000);
|
||||
else if (id === "quickSave") quickSave();
|
||||
else if (id === "saveMap") saveMap();
|
||||
else if (id === "saveSVG") saveAsImage("svg");
|
||||
else if (id === "savePNG") saveAsImage("png");
|
||||
else if (id === "saveDropbox") saveDropbox();
|
||||
if (id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveDropbox") toggleSavePane();
|
||||
if (id === "loadMap") mapToLoad.click()
|
||||
if (id === "loadURL") loadURL();
|
||||
if (id === "loadDropbox") loadDropbox();
|
||||
if (id === "loadURL" || id === "loadMap" || id === "loadDropbox") toggleLoadPane();
|
||||
if (id === "quickSave" || id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveDropbox") toggleSavePane();
|
||||
if (id === "loadMap") mapToLoad.click();
|
||||
else if (id === "quickLoad") quickLoad();
|
||||
else if (id === "loadURL") loadURL();
|
||||
else if (id === "loadDropbox") loadDropbox();
|
||||
if (id === "quickLoad" || id === "loadURL" || id === "loadMap" || id === "loadDropbox") toggleLoadPane();
|
||||
});
|
||||
|
||||
function regeneratePrompt() {
|
||||
if (customization) {tip("Please exit the customization mode first", false, "warning"); return;}
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 15) {regenerateMap(); return;}
|
||||
if (workingTime < 10) {regenerateMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({resizable: false, title: "Generate new map",
|
||||
buttons: {
|
||||
Cancel: function() {$(this).dialog("close");},
|
||||
Generate: regenerateMap
|
||||
Generate: function() {closeDialogs(); regenerateMap();}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1052,7 +1047,8 @@ function toggleSavePane() {
|
|||
// };
|
||||
|
||||
// // working file: "https://dl.dropbox.com/s/llg93mwyonyzdmu/test.map?dl=1";
|
||||
// const URL = await getMapURL();
|
||||
// const dataBlob = await getMapData();
|
||||
// const URL = window.URL.createObjectURL(dataBlob);
|
||||
// Dropbox.save(URL, filename, options);
|
||||
// }
|
||||
|
||||
|
|
@ -1072,6 +1068,7 @@ function loadURL() {
|
|||
Load: function() {
|
||||
const value = mapURL.value;
|
||||
if (!pattern.test(value)) {tip("Please provide a valid URL", false, "error"); return;}
|
||||
closeDialogs();
|
||||
loadMapFromURL(value);
|
||||
$(this).dialog("close");
|
||||
},
|
||||
|
|
@ -1104,5 +1101,6 @@ function loadURL() {
|
|||
document.getElementById("mapToLoad").addEventListener("change", function() {
|
||||
const fileToLoad = this.files[0];
|
||||
this.value = "";
|
||||
closeDialogs();
|
||||
uploadFile(fileToLoad);
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue