mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 20:11:24 +01:00
remove unused files
This commit is contained in:
parent
1776fa8917
commit
5beb497026
5 changed files with 0 additions and 1415 deletions
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"bracketSpacing": false,
|
|
||||||
"semi": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"printWidth": 200,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"endOfLine": "lf"
|
|
||||||
}
|
|
||||||
2
libs/dropins.min.js
vendored
2
libs/dropins.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,523 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// update old .map version to the current one
|
|
||||||
export function resolveVersionConflicts(version) {
|
|
||||||
if (version < 1) {
|
|
||||||
// v1.0 added a new religions layer
|
|
||||||
relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
|
||||||
Religions.generate();
|
|
||||||
|
|
||||||
// v1.0 added a legend box
|
|
||||||
legend = svg.append("g").attr("id", "legend");
|
|
||||||
legend
|
|
||||||
.attr("font-family", "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");
|
|
||||||
|
|
||||||
// v1.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", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
|
|
||||||
provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
|
|
||||||
|
|
||||||
// v1.0 added state relations, provinces, forms and full names
|
|
||||||
provs = viewbox.insert("g", "#borders").attr("id", "provs").attr("opacity", 0.6);
|
|
||||||
BurgsAndStates.collectStatistics();
|
|
||||||
BurgsAndStates.generateCampaigns();
|
|
||||||
BurgsAndStates.generateDiplomacy();
|
|
||||||
BurgsAndStates.defineStateForms();
|
|
||||||
drawStates();
|
|
||||||
BurgsAndStates.generateProvinces();
|
|
||||||
drawBorders();
|
|
||||||
if (!layerIsOn("toggleBorders")) $("#borders").fadeOut();
|
|
||||||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
|
||||||
|
|
||||||
// v1.0 added zones layer
|
|
||||||
zones = viewbox.insert("g", "#borders").attr("id", "zones").attr("display", "none");
|
|
||||||
zones.attr("opacity", 0.6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt");
|
|
||||||
addZones();
|
|
||||||
if (!markers.selectAll("*").size()) {
|
|
||||||
Markers.generate();
|
|
||||||
turnButtonOn("toggleMarkers");
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.0 add fogging layer (state focus)
|
|
||||||
fogging = viewbox.insert("g", "#ruler").attr("id", "fogging-cont").attr("mask", "url(#fog)").append("g").attr("id", "fogging").style("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");
|
|
||||||
|
|
||||||
// v1.0 changes states opacity bask to regions level
|
|
||||||
if (statesBody.attr("opacity")) {
|
|
||||||
regions.attr("opacity", statesBody.attr("opacity"));
|
|
||||||
statesBody.attr("opacity", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.0 changed labels to multi-lined
|
|
||||||
labels.selectAll("textPath").each(function () {
|
|
||||||
const text = this.textContent;
|
|
||||||
const shift = this.getComputedTextLength() / -1.5;
|
|
||||||
this.innerHTML = /* html */ `<tspan x="${shift}">${text}</tspan>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// v1.0 added new biome - Wetland
|
|
||||||
biomesData.name.push("Wetland");
|
|
||||||
biomesData.color.push("#0b9131");
|
|
||||||
biomesData.habitability.push(12);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.1) {
|
|
||||||
// v1.0 initial code had a bug with religion layer id
|
|
||||||
if (!relig.size()) relig = viewbox.insert("g", "#terrain").attr("id", "relig");
|
|
||||||
|
|
||||||
// v1.0 initially has Sympathy status then relaced with Friendly
|
|
||||||
for (const s of pack.states) {
|
|
||||||
if (!s.diplomacy) continue;
|
|
||||||
s.diplomacy = s.diplomacy.map(r => (r === "Sympathy" ? "Friendly" : r));
|
|
||||||
}
|
|
||||||
|
|
||||||
// labels should be toggled via style attribute, so remove display attribute
|
|
||||||
labels.attr("display", null);
|
|
||||||
|
|
||||||
// v1.0 added religions heirarchy tree
|
|
||||||
if (pack.religions[1] && !pack.religions[1].code) {
|
|
||||||
pack.religions
|
|
||||||
.filter(r => r.i)
|
|
||||||
.forEach(r => {
|
|
||||||
r.origin = 0;
|
|
||||||
r.code = r.name.slice(0, 2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!document.getElementById("freshwater")) {
|
|
||||||
lakes.append("g").attr("id", "freshwater");
|
|
||||||
lakes.select("#freshwater").attr("opacity", 0.5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", 0.7).attr("filter", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!document.getElementById("salt")) {
|
|
||||||
lakes.append("g").attr("id", "salt");
|
|
||||||
lakes.select("#salt").attr("opacity", 0.5).attr("fill", "#409b8a").attr("stroke", "#388985").attr("stroke-width", 0.7).attr("filter", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.1 added new lake and coast groups
|
|
||||||
if (!document.getElementById("sinkhole")) {
|
|
||||||
lakes.append("g").attr("id", "sinkhole");
|
|
||||||
lakes.append("g").attr("id", "frozen");
|
|
||||||
lakes.append("g").attr("id", "lava");
|
|
||||||
lakes.select("#sinkhole").attr("opacity", 1).attr("fill", "#5bc9fd").attr("stroke", "#53a3b0").attr("stroke-width", 0.7).attr("filter", null);
|
|
||||||
lakes.select("#frozen").attr("opacity", 0.95).attr("fill", "#cdd4e7").attr("stroke", "#cfe0eb").attr("stroke-width", 0).attr("filter", null);
|
|
||||||
lakes.select("#lava").attr("opacity", 0.7).attr("fill", "#90270d").attr("stroke", "#f93e0c").attr("stroke-width", 2).attr("filter", "url(#crumpled)");
|
|
||||||
|
|
||||||
coastline.append("g").attr("id", "sea_island");
|
|
||||||
coastline.append("g").attr("id", "lake_island");
|
|
||||||
coastline.select("#sea_island").attr("opacity", 0.5).attr("stroke", "#1f3846").attr("stroke-width", 0.7).attr("filter", "url(#dropShadow)");
|
|
||||||
coastline.select("#lake_island").attr("opacity", 1).attr("stroke", "#7c8eaf").attr("stroke-width", 0.35).attr("filter", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.1 features stores more data
|
|
||||||
defs.select("#land").selectAll("path").remove();
|
|
||||||
defs.select("#water").selectAll("path").remove();
|
|
||||||
coastline.selectAll("path").remove();
|
|
||||||
lakes.selectAll("path").remove();
|
|
||||||
drawCoastline();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.11) {
|
|
||||||
// v1.11 added new attributes
|
|
||||||
terrs.attr("scheme", "bright").attr("terracing", 0).attr("skip", 5).attr("relax", 0).attr("curve", 0);
|
|
||||||
svg.select("#oceanic > *").attr("id", "oceanicPattern");
|
|
||||||
oceanLayers.attr("layers", "-6,-3,-1");
|
|
||||||
gridOverlay.attr("type", "pointyHex").attr("size", 10);
|
|
||||||
|
|
||||||
// v1.11 added cultures heirarchy tree
|
|
||||||
if (pack.cultures[1] && !pack.cultures[1].code) {
|
|
||||||
pack.cultures
|
|
||||||
.filter(c => c.i)
|
|
||||||
.forEach(c => {
|
|
||||||
c.origin = 0;
|
|
||||||
c.code = c.name.slice(0, 2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.11 had an issue with fogging being displayed on load
|
|
||||||
unfog();
|
|
||||||
|
|
||||||
// v1.2 added new terrain attributes
|
|
||||||
if (!terrain.attr("set")) terrain.attr("set", "simple");
|
|
||||||
if (!terrain.attr("size")) terrain.attr("size", 1);
|
|
||||||
if (!terrain.attr("density")) terrain.attr("density", 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.21) {
|
|
||||||
// v1.11 replaced "display" attribute by "display" style
|
|
||||||
viewbox.selectAll("g").each(function () {
|
|
||||||
if (this.hasAttribute("display")) {
|
|
||||||
this.removeAttribute("display");
|
|
||||||
this.style.display = "none";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// v1.21 added rivers data to pack
|
|
||||||
pack.rivers = []; // rivers data
|
|
||||||
rivers.selectAll("path").each(function () {
|
|
||||||
const i = +this.id.slice(5);
|
|
||||||
const length = this.getTotalLength() / 2;
|
|
||||||
const s = this.getPointAtLength(length),
|
|
||||||
e = this.getPointAtLength(0);
|
|
||||||
const source = findCell(s.x, s.y),
|
|
||||||
mouth = findCell(e.x, e.y);
|
|
||||||
const name = Rivers.getName(mouth);
|
|
||||||
const type = length < 25 ? rw({Creek: 9, River: 3, Brook: 3, Stream: 1}) : "River";
|
|
||||||
pack.rivers.push({i, parent: 0, length, source, mouth, basin: i, name, type});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.22) {
|
|
||||||
// v1.22 changed state neighbors from Set object to array
|
|
||||||
BurgsAndStates.collectStatistics();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.3) {
|
|
||||||
// v1.3 added global options object
|
|
||||||
const winds = options.slice(); // previostly wind was saved in settings[19]
|
|
||||||
const year = rand(100, 2000);
|
|
||||||
const era = Names.getBaseShort(P(0.7) ? 1 : rand(nameBases.length)) + " Era";
|
|
||||||
const eraShort = era[0] + "E";
|
|
||||||
const military = Military.getDefaultOptions();
|
|
||||||
options = {winds, year, era, eraShort, military};
|
|
||||||
|
|
||||||
// v1.3 added campaings data for all states
|
|
||||||
BurgsAndStates.generateCampaigns();
|
|
||||||
|
|
||||||
// v1.3 added militry layer
|
|
||||||
armies = viewbox.insert("g", "#icons").attr("id", "armies");
|
|
||||||
armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", 0.3);
|
|
||||||
turnButtonOn("toggleMilitary");
|
|
||||||
Military.generate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.4) {
|
|
||||||
// v1.35 added dry lakes
|
|
||||||
if (!lakes.select("#dry").size()) {
|
|
||||||
lakes.append("g").attr("id", "dry");
|
|
||||||
lakes.select("#dry").attr("opacity", 1).attr("fill", "#c9bfa7").attr("stroke", "#8e816f").attr("stroke-width", 0.7).attr("filter", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.4 added ice layer
|
|
||||||
ice = viewbox.insert("g", "#coastline").attr("id", "ice").style("display", "none");
|
|
||||||
ice.attr("opacity", null).attr("fill", "#e8f0f6").attr("stroke", "#e8f0f6").attr("stroke-width", 1).attr("filter", "url(#dropShadow05)");
|
|
||||||
drawIce();
|
|
||||||
|
|
||||||
// v1.4 added icon and power attributes for units
|
|
||||||
for (const unit of options.military) {
|
|
||||||
if (!unit.icon) unit.icon = getUnitIcon(unit.type);
|
|
||||||
if (!unit.power) unit.power = unit.crew;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUnitIcon(type) {
|
|
||||||
if (type === "naval") return "🌊";
|
|
||||||
if (type === "ranged") return "🏹";
|
|
||||||
if (type === "mounted") return "🐴";
|
|
||||||
if (type === "machinery") return "💣";
|
|
||||||
if (type === "armored") return "🐢";
|
|
||||||
if (type === "aviation") return "🦅";
|
|
||||||
if (type === "magical") return "🔮";
|
|
||||||
else return "⚔️";
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.4 added state reference for regiments
|
|
||||||
pack.states.filter(s => s.military).forEach(s => s.military.forEach(r => (r.state = s.i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.5) {
|
|
||||||
// not need to store default styles from v 1.5
|
|
||||||
localStorage.removeItem("styleClean");
|
|
||||||
localStorage.removeItem("styleGloom");
|
|
||||||
localStorage.removeItem("styleAncient");
|
|
||||||
localStorage.removeItem("styleMonochrome");
|
|
||||||
|
|
||||||
// v1.5 cultures has shield attribute
|
|
||||||
pack.cultures.forEach(culture => {
|
|
||||||
if (culture.removed) return;
|
|
||||||
culture.shield = Cultures.getRandomShield();
|
|
||||||
});
|
|
||||||
|
|
||||||
// v1.5 added burg type value
|
|
||||||
pack.burgs.forEach(burg => {
|
|
||||||
if (!burg.i || burg.removed) return;
|
|
||||||
burg.type = BurgsAndStates.getType(burg.cell, burg.port);
|
|
||||||
});
|
|
||||||
|
|
||||||
// v1.5 added emblems
|
|
||||||
defs.append("g").attr("id", "defs-emblems");
|
|
||||||
emblems = viewbox.insert("g", "#population").attr("id", "emblems").style("display", "none");
|
|
||||||
emblems.append("g").attr("id", "burgEmblems");
|
|
||||||
emblems.append("g").attr("id", "provinceEmblems");
|
|
||||||
emblems.append("g").attr("id", "stateEmblems");
|
|
||||||
regenerateEmblems();
|
|
||||||
toggleEmblems();
|
|
||||||
|
|
||||||
// v1.5 changed releif icons data
|
|
||||||
terrain.selectAll("use").each(function () {
|
|
||||||
const type = this.getAttribute("data-type") || this.getAttribute("xlink:href");
|
|
||||||
this.removeAttribute("xlink:href");
|
|
||||||
this.removeAttribute("data-type");
|
|
||||||
this.removeAttribute("data-size");
|
|
||||||
this.setAttribute("href", type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.6) {
|
|
||||||
// v1.6 changed rivers data
|
|
||||||
for (const river of pack.rivers) {
|
|
||||||
const el = document.getElementById("river" + river.i);
|
|
||||||
if (el) {
|
|
||||||
river.widthFactor = +el.getAttribute("data-width");
|
|
||||||
el.removeAttribute("data-width");
|
|
||||||
el.removeAttribute("data-increment");
|
|
||||||
river.discharge = pack.cells.fl[river.mouth] || 1;
|
|
||||||
river.width = rn(river.length / 100, 2);
|
|
||||||
river.sourceWidth = 0.1;
|
|
||||||
} else {
|
|
||||||
Rivers.remove(river.i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// v1.6 changed lakes data
|
|
||||||
for (const f of pack.features) {
|
|
||||||
if (f.type !== "lake") continue;
|
|
||||||
if (f.evaporation) continue;
|
|
||||||
|
|
||||||
f.flux = f.flux || f.cells * 3;
|
|
||||||
f.temp = grid.cells.temp[pack.cells.g[f.firstCell]];
|
|
||||||
f.height = f.height || d3.min(pack.cells.c[f.firstCell].map(c => pack.cells.h[c]).filter(h => h >= 20));
|
|
||||||
const height = (f.height - 18) ** heightExponentInput.value;
|
|
||||||
const evaporation = ((700 * (f.temp + 0.006 * height)) / 50 + 75) / (80 - f.temp);
|
|
||||||
f.evaporation = rn(evaporation * f.cells);
|
|
||||||
f.name = f.name || Lakes.getName(f);
|
|
||||||
delete f.river;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.61) {
|
|
||||||
// v1.61 changed rulers data
|
|
||||||
ruler.style("display", null);
|
|
||||||
rulers = new Rulers();
|
|
||||||
|
|
||||||
ruler.selectAll(".ruler > .white").each(function () {
|
|
||||||
const x1 = +this.getAttribute("x1");
|
|
||||||
const y1 = +this.getAttribute("y1");
|
|
||||||
const x2 = +this.getAttribute("x2");
|
|
||||||
const y2 = +this.getAttribute("y2");
|
|
||||||
if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) return;
|
|
||||||
const points = [
|
|
||||||
[x1, y1],
|
|
||||||
[x2, y2]
|
|
||||||
];
|
|
||||||
rulers.create(Ruler, points);
|
|
||||||
});
|
|
||||||
|
|
||||||
ruler.selectAll("g.opisometer").each(function () {
|
|
||||||
const pointsString = this.dataset.points;
|
|
||||||
if (!pointsString) return;
|
|
||||||
const points = JSON.parse(pointsString);
|
|
||||||
rulers.create(Opisometer, points);
|
|
||||||
});
|
|
||||||
|
|
||||||
ruler.selectAll("path.planimeter").each(function () {
|
|
||||||
const length = this.getTotalLength();
|
|
||||||
if (length < 30) return;
|
|
||||||
|
|
||||||
const step = length > 1000 ? 40 : length > 400 ? 20 : 10;
|
|
||||||
const increment = length / Math.ceil(length / step);
|
|
||||||
const points = [];
|
|
||||||
for (let i = 0; i <= length; i += increment) {
|
|
||||||
const point = this.getPointAtLength(i);
|
|
||||||
points.push([point.x | 0, point.y | 0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
rulers.create(Planimeter, points);
|
|
||||||
});
|
|
||||||
|
|
||||||
ruler.selectAll("*").remove();
|
|
||||||
|
|
||||||
if (rulers.data.length) {
|
|
||||||
turnButtonOn("toggleRulers");
|
|
||||||
rulers.draw();
|
|
||||||
} else turnButtonOff("toggleRulers");
|
|
||||||
|
|
||||||
// 1.61 changed oceanicPattern from rect to image
|
|
||||||
const pattern = document.getElementById("oceanic");
|
|
||||||
const filter = pattern.firstElementChild.getAttribute("filter");
|
|
||||||
const href = filter ? "./images/" + filter.replace("url(#", "").replace(")", "") + ".png" : "";
|
|
||||||
pattern.innerHTML = /* html */ `<image id="oceanicPattern" href=${href} width="100" height="100" opacity="0.2"></image>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.62) {
|
|
||||||
// v1.62 changed grid data
|
|
||||||
gridOverlay.attr("size", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.63) {
|
|
||||||
// v1.63 changed ocean pattern opacity element
|
|
||||||
const oceanPattern = document.getElementById("oceanPattern");
|
|
||||||
if (oceanPattern) oceanPattern.removeAttribute("opacity");
|
|
||||||
const oceanicPattern = document.getElementById("oceanicPattern");
|
|
||||||
if (!oceanicPattern.getAttribute("opacity")) oceanicPattern.setAttribute("opacity", 0.2);
|
|
||||||
|
|
||||||
// v 1.63 moved label text-shadow from css to editable inline style
|
|
||||||
burgLabels.select("#cities").style("text-shadow", "white 0 0 4px");
|
|
||||||
burgLabels.select("#towns").style("text-shadow", "white 0 0 4px");
|
|
||||||
labels.select("#states").style("text-shadow", "white 0 0 4px");
|
|
||||||
labels.select("#addedLabels").style("text-shadow", "white 0 0 4px");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.64) {
|
|
||||||
// v1.64 change states style
|
|
||||||
const opacity = regions.attr("opacity");
|
|
||||||
const filter = regions.attr("filter");
|
|
||||||
statesBody.attr("opacity", opacity).attr("filter", filter);
|
|
||||||
statesHalo.attr("opacity", opacity).attr("filter", "blur(5px)");
|
|
||||||
regions.attr("opacity", null).attr("filter", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.65) {
|
|
||||||
// v1.65 changed rivers data
|
|
||||||
d3.select("#rivers").attr("style", null); // remove style to unhide layer
|
|
||||||
const {cells, rivers} = pack;
|
|
||||||
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
|
|
||||||
|
|
||||||
for (const river of rivers) {
|
|
||||||
const node = document.getElementById("river" + river.i);
|
|
||||||
if (node && !river.cells) {
|
|
||||||
const riverCells = [];
|
|
||||||
const riverPoints = [];
|
|
||||||
|
|
||||||
const length = node.getTotalLength() / 2;
|
|
||||||
if (!length) continue;
|
|
||||||
const segments = Math.ceil(length / 6);
|
|
||||||
const increment = length / segments;
|
|
||||||
|
|
||||||
for (let i = 0; i <= segments; i++) {
|
|
||||||
const shift = increment * i;
|
|
||||||
const {x: x1, y: y1} = node.getPointAtLength(length + shift);
|
|
||||||
const {x: x2, y: y2} = node.getPointAtLength(length - shift);
|
|
||||||
const x = rn((x1 + x2) / 2, 1);
|
|
||||||
const y = rn((y1 + y2) / 2, 1);
|
|
||||||
|
|
||||||
const cell = findCell(x, y);
|
|
||||||
riverPoints.push([x, y]);
|
|
||||||
riverCells.push(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
river.cells = riverCells;
|
|
||||||
river.points = riverPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
river.widthFactor = defaultWidthFactor;
|
|
||||||
|
|
||||||
cells.i.forEach(i => {
|
|
||||||
const riverInWater = cells.r[i] && cells.h[i] < 20;
|
|
||||||
if (riverInWater) cells.r[i] = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.652) {
|
|
||||||
// remove style to unhide layers
|
|
||||||
rivers.attr("style", null);
|
|
||||||
borders.attr("style", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.7) {
|
|
||||||
// v1.7 changed markers data
|
|
||||||
const defs = document.getElementById("defs-markers");
|
|
||||||
const markersGroup = document.getElementById("markers");
|
|
||||||
|
|
||||||
if (defs && markersGroup) {
|
|
||||||
const markerElements = markersGroup.querySelectorAll("use");
|
|
||||||
const rescale = +markersGroup.getAttribute("rescale");
|
|
||||||
|
|
||||||
pack.markers = Array.from(markerElements).map((el, i) => {
|
|
||||||
const id = el.getAttribute("id");
|
|
||||||
const note = notes.find(note => note.id === id);
|
|
||||||
if (note) note.id = `marker${i}`;
|
|
||||||
|
|
||||||
let x = +el.dataset.x;
|
|
||||||
let y = +el.dataset.y;
|
|
||||||
|
|
||||||
const transform = el.getAttribute("transform");
|
|
||||||
if (transform) {
|
|
||||||
const [dx, dy] = parseTransform(transform);
|
|
||||||
if (dx) x += +dx;
|
|
||||||
if (dy) y += +dy;
|
|
||||||
}
|
|
||||||
const cell = findCell(x, y);
|
|
||||||
const size = rn(rescale ? el.dataset.size * 30 : el.getAttribute("width"), 1);
|
|
||||||
|
|
||||||
const href = el.href.baseVal;
|
|
||||||
const type = href.replace("#marker_", "");
|
|
||||||
const symbol = defs?.querySelector(`symbol${href}`);
|
|
||||||
const text = symbol?.querySelector("text");
|
|
||||||
const circle = symbol?.querySelector("circle");
|
|
||||||
|
|
||||||
const icon = text?.innerHTML;
|
|
||||||
const px = text && Number(text.getAttribute("font-size")?.replace("px", ""));
|
|
||||||
const dx = text && Number(text.getAttribute("x")?.replace("%", ""));
|
|
||||||
const dy = text && Number(text.getAttribute("y")?.replace("%", ""));
|
|
||||||
const fill = circle && circle.getAttribute("fill");
|
|
||||||
const stroke = circle && circle.getAttribute("stroke");
|
|
||||||
|
|
||||||
const marker = {i, icon, type, x, y, size, cell};
|
|
||||||
if (size && size !== 30) marker.size = size;
|
|
||||||
if (!isNaN(px) && px !== 12) marker.px = px;
|
|
||||||
if (!isNaN(dx) && dx !== 50) marker.dx = dx;
|
|
||||||
if (!isNaN(dy) && dy !== 50) marker.dy = dy;
|
|
||||||
if (fill && fill !== "#ffffff") marker.fill = fill;
|
|
||||||
if (stroke && stroke !== "#000000") marker.stroke = stroke;
|
|
||||||
if (circle?.getAttribute("opacity") === "0") marker.pin = "no";
|
|
||||||
|
|
||||||
return marker;
|
|
||||||
});
|
|
||||||
|
|
||||||
markersGroup.style.display = null;
|
|
||||||
defs?.remove();
|
|
||||||
markerElements.forEach(el => el.remove());
|
|
||||||
if (layerIsOn("markers")) drawMarkers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.72) {
|
|
||||||
// v1.72 renamed custom style presets
|
|
||||||
const storedStyles = Object.keys(localStorage).filter(key => key.startsWith("style"));
|
|
||||||
storedStyles.forEach(styleName => {
|
|
||||||
const style = localStorage.getItem(styleName);
|
|
||||||
const newStyleName = styleName.replace(/^style/, customPresetPrefix);
|
|
||||||
localStorage.setItem(newStyleName, style);
|
|
||||||
localStorage.removeItem(styleName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 1.73) {
|
|
||||||
// v1.73 moved the hatching patterns out of the user's SVG
|
|
||||||
document.getElementById("hatching")?.remove();
|
|
||||||
|
|
||||||
// v1.73 added zone type to UI, ensure type is populated
|
|
||||||
const zones = Array.from(document.querySelectorAll("#zones > g"));
|
|
||||||
zones.forEach(zone => {
|
|
||||||
if (!zone.dataset.type) zone.dataset.type = "Unknown";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,235 +0,0 @@
|
||||||
export function exportToJson(type) {
|
|
||||||
if (customization)
|
|
||||||
return tip("Data cannot be exported when edit mode is active, please exit the mode and retry", false, "error");
|
|
||||||
closeDialogs("#alert");
|
|
||||||
|
|
||||||
const typeMap = {
|
|
||||||
Full: getFullDataJson,
|
|
||||||
Minimal: getMinimalDataJson,
|
|
||||||
PackCells: getPackCellsDataJson,
|
|
||||||
GridCells: getGridCellsDataJson
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapData = typeMap[type]();
|
|
||||||
const blob = new Blob([mapData], {type: "application/json"});
|
|
||||||
const URL = window.URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.download = getFileName(type) + ".json";
|
|
||||||
link.href = URL;
|
|
||||||
link.click();
|
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
|
||||||
window.URL.revokeObjectURL(URL);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFullDataJson() {
|
|
||||||
TIME && console.time("getFullDataJson");
|
|
||||||
|
|
||||||
const info = getMapInfo();
|
|
||||||
const settings = getSettings();
|
|
||||||
const cells = getPackCellsData();
|
|
||||||
const vertices = getPackVerticesData();
|
|
||||||
const exportData = {info, settings, coords: mapCoordinates, cells, vertices, biomes: biomesData, notes, nameBases};
|
|
||||||
|
|
||||||
TIME && console.timeEnd("getFullDataJson");
|
|
||||||
return JSON.stringify(exportData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMinimalDataJson() {
|
|
||||||
TIME && console.time("getMinimalDataJson");
|
|
||||||
|
|
||||||
const info = getMapInfo();
|
|
||||||
const settings = getSettings();
|
|
||||||
const packData = {
|
|
||||||
features: pack.features,
|
|
||||||
cultures: pack.cultures,
|
|
||||||
burgs: pack.burgs,
|
|
||||||
states: pack.states,
|
|
||||||
provinces: pack.provinces,
|
|
||||||
religions: pack.religions,
|
|
||||||
rivers: pack.rivers,
|
|
||||||
markers: pack.markers
|
|
||||||
};
|
|
||||||
const exportData = {info, settings, coords: mapCoordinates, pack: packData, biomes: biomesData, notes, nameBases};
|
|
||||||
|
|
||||||
TIME && console.timeEnd("getMinimalDataJson");
|
|
||||||
return JSON.stringify(exportData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPackCellsDataJson() {
|
|
||||||
TIME && console.time("getCellsDataJson");
|
|
||||||
|
|
||||||
const info = getMapInfo();
|
|
||||||
const cells = getPackCellsData();
|
|
||||||
const exportData = {info, cells};
|
|
||||||
|
|
||||||
TIME && console.timeEnd("getCellsDataJson");
|
|
||||||
return JSON.stringify(exportData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGridCellsDataJson() {
|
|
||||||
TIME && console.time("getGridCellsDataJson");
|
|
||||||
|
|
||||||
const info = getMapInfo();
|
|
||||||
const gridCells = getGridCellsData();
|
|
||||||
const exportData = {info, gridCells};
|
|
||||||
|
|
||||||
TIME && console.log("getGridCellsDataJson");
|
|
||||||
return JSON.stringify(exportData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMapInfo() {
|
|
||||||
const info = {
|
|
||||||
version,
|
|
||||||
description: "Azgaar's Fantasy Map Generator output: azgaar.github.io/Fantasy-map-generator",
|
|
||||||
exportedAt: new Date().toISOString(),
|
|
||||||
mapName: mapName.value,
|
|
||||||
seed,
|
|
||||||
mapId
|
|
||||||
};
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSettings() {
|
|
||||||
const settings = {
|
|
||||||
distanceUnit: distanceUnitInput.value,
|
|
||||||
distanceScale: distanceScaleInput.value,
|
|
||||||
areaUnit: areaUnit.value,
|
|
||||||
heightUnit: heightUnit.value,
|
|
||||||
heightExponent: heightExponentInput.value,
|
|
||||||
temperatureScale: temperatureScale.value,
|
|
||||||
barSize: barSizeInput.value,
|
|
||||||
barLabel: barLabel.value,
|
|
||||||
barBackOpacity: barBackOpacity.value,
|
|
||||||
barBackColor: barBackColor.value,
|
|
||||||
barPosX: barPosX.value,
|
|
||||||
barPosY: barPosY.value,
|
|
||||||
populationRate: populationRate,
|
|
||||||
urbanization: urbanization,
|
|
||||||
mapSize: mapSizeOutput.value,
|
|
||||||
latitudeO: latitudeOutput.value,
|
|
||||||
temperatureEquator: temperatureEquatorOutput.value,
|
|
||||||
temperaturePole: temperaturePoleOutput.value,
|
|
||||||
prec: precOutput.value,
|
|
||||||
options: options,
|
|
||||||
mapName: mapName.value,
|
|
||||||
hideLabels: hideLabels.checked,
|
|
||||||
stylePreset: stylePreset.value,
|
|
||||||
rescaleLabels: rescaleLabels.checked,
|
|
||||||
urbanDensity: urbanDensity
|
|
||||||
};
|
|
||||||
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPackCellsData() {
|
|
||||||
const cellConverted = {
|
|
||||||
i: Array.from(pack.cells.i),
|
|
||||||
v: pack.cells.v,
|
|
||||||
c: pack.cells.c,
|
|
||||||
p: pack.cells.p,
|
|
||||||
g: Array.from(pack.cells.g),
|
|
||||||
h: Array.from(pack.cells.h),
|
|
||||||
area: Array.from(pack.cells.area),
|
|
||||||
f: Array.from(pack.cells.f),
|
|
||||||
t: Array.from(pack.cells.t),
|
|
||||||
haven: Array.from(pack.cells.haven),
|
|
||||||
harbor: Array.from(pack.cells.harbor),
|
|
||||||
fl: Array.from(pack.cells.fl),
|
|
||||||
r: Array.from(pack.cells.r),
|
|
||||||
conf: Array.from(pack.cells.conf),
|
|
||||||
biome: Array.from(pack.cells.biome),
|
|
||||||
s: Array.from(pack.cells.s),
|
|
||||||
pop: Array.from(pack.cells.pop),
|
|
||||||
culture: Array.from(pack.cells.culture),
|
|
||||||
burg: Array.from(pack.cells.burg),
|
|
||||||
road: Array.from(pack.cells.road),
|
|
||||||
crossroad: Array.from(pack.cells.crossroad),
|
|
||||||
state: Array.from(pack.cells.state),
|
|
||||||
religion: Array.from(pack.cells.religion),
|
|
||||||
province: Array.from(pack.cells.province)
|
|
||||||
};
|
|
||||||
const cellObjArr = [];
|
|
||||||
{
|
|
||||||
cellConverted.i.forEach(value => {
|
|
||||||
const cellobj = {
|
|
||||||
i: value,
|
|
||||||
v: cellConverted.v[value],
|
|
||||||
c: cellConverted.c[value],
|
|
||||||
p: cellConverted.p[value],
|
|
||||||
g: cellConverted.g[value],
|
|
||||||
h: cellConverted.h[value],
|
|
||||||
area: cellConverted.area[value],
|
|
||||||
f: cellConverted.f[value],
|
|
||||||
t: cellConverted.t[value],
|
|
||||||
haven: cellConverted.haven[value],
|
|
||||||
harbor: cellConverted.harbor[value],
|
|
||||||
fl: cellConverted.fl[value],
|
|
||||||
r: cellConverted.r[value],
|
|
||||||
conf: cellConverted.conf[value],
|
|
||||||
biome: cellConverted.biome[value],
|
|
||||||
s: cellConverted.s[value],
|
|
||||||
pop: cellConverted.pop[value],
|
|
||||||
culture: cellConverted.culture[value],
|
|
||||||
burg: cellConverted.burg[value],
|
|
||||||
road: cellConverted.road[value],
|
|
||||||
crossroad: cellConverted.crossroad[value],
|
|
||||||
state: cellConverted.state[value],
|
|
||||||
religion: cellConverted.religion[value],
|
|
||||||
province: cellConverted.province[value]
|
|
||||||
};
|
|
||||||
cellObjArr.push(cellobj);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const cellsData = {
|
|
||||||
cells: cellObjArr,
|
|
||||||
features: pack.features,
|
|
||||||
cultures: pack.cultures,
|
|
||||||
burgs: pack.burgs,
|
|
||||||
states: pack.states,
|
|
||||||
provinces: pack.provinces,
|
|
||||||
religions: pack.religions,
|
|
||||||
rivers: pack.rivers,
|
|
||||||
markers: pack.markers
|
|
||||||
};
|
|
||||||
|
|
||||||
return cellsData;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGridCellsData() {
|
|
||||||
const gridData = {
|
|
||||||
cellsDesired: grid.cellsDesired,
|
|
||||||
spacing: grid.spacing,
|
|
||||||
cellsY: grid.cellsY,
|
|
||||||
cellsX: grid.cellsX,
|
|
||||||
points: grid.points,
|
|
||||||
boundary: grid.boundary
|
|
||||||
};
|
|
||||||
return gridData;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPackVerticesData() {
|
|
||||||
const {vertices} = pack;
|
|
||||||
const verticesNumber = vertices.p.length;
|
|
||||||
const verticesArray = new Array(verticesNumber);
|
|
||||||
for (let i = 0; i < verticesNumber; i++) {
|
|
||||||
verticesArray[i] = {
|
|
||||||
p: vertices.p[i],
|
|
||||||
v: vertices.v[i],
|
|
||||||
c: vertices.c[i]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return verticesArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGridCellsDataJson() {
|
|
||||||
TIME && console.time("getGridCellsDataJson");
|
|
||||||
|
|
||||||
const info = getMapInfo();
|
|
||||||
const gridCells = getGridCellsData()
|
|
||||||
const exportData = {info,gridCells};
|
|
||||||
|
|
||||||
TIME && console.log("getGridCellsDataJson");
|
|
||||||
return JSON.stringify(exportData);
|
|
||||||
}
|
|
||||||
|
|
@ -1,645 +0,0 @@
|
||||||
"use strict";
|
|
||||||
function editResources() {
|
|
||||||
if (customization) return;
|
|
||||||
closeDialogs('#resourcesEditor, .stable');
|
|
||||||
if (!layerIsOn('toggleResources')) toggleResources();
|
|
||||||
const body = document.getElementById('resourcesBody');
|
|
||||||
|
|
||||||
resourcesEditorAddLines();
|
|
||||||
|
|
||||||
if (modules.editResources) return;
|
|
||||||
modules.editResources = true;
|
|
||||||
|
|
||||||
$('#resourcesEditor').dialog({
|
|
||||||
title: 'Resources Editor',
|
|
||||||
resizable: false,
|
|
||||||
width: fitContent(),
|
|
||||||
close: closeResourcesEditor,
|
|
||||||
position: {my: 'right top', at: 'right-10 top+10', of: 'svg'}
|
|
||||||
});
|
|
||||||
|
|
||||||
// add listeners
|
|
||||||
document.getElementById('resourcesEditorRefresh').addEventListener('click', resourcesEditorAddLines);
|
|
||||||
document.getElementById('resourcesRegenerate').addEventListener('click', regenerateCurrentResources);
|
|
||||||
document.getElementById('resourcesLegend').addEventListener('click', toggleLegend);
|
|
||||||
document.getElementById('resourcesPercentage').addEventListener('click', togglePercentageMode);
|
|
||||||
document.getElementById('resourcesAssign').addEventListener('click', enterResourceAssignMode);
|
|
||||||
document.getElementById('resourcesAdd').addEventListener('click', resourceAdd);
|
|
||||||
document.getElementById('resourcesRestore').addEventListener('click', resourcesRestoreDefaults);
|
|
||||||
document.getElementById('resourcesExport').addEventListener('click', downloadResourcesData);
|
|
||||||
document.getElementById('resourcesUnpinAll').addEventListener('click', unpinAllResources);
|
|
||||||
|
|
||||||
body.addEventListener('click', function (ev) {
|
|
||||||
const el = ev.target,
|
|
||||||
cl = el.classList,
|
|
||||||
line = el.parentNode;
|
|
||||||
const resource = Resources.get(+line.dataset.id);
|
|
||||||
if (cl.contains('resourceIcon')) return changeIcon(resource, line, el);
|
|
||||||
if (cl.contains('resourceCategory')) return changeCategory(resource, line, el);
|
|
||||||
if (cl.contains('resourceModel')) return changeModel(resource, line, el);
|
|
||||||
if (cl.contains('resourceBonus')) return changeBonus(resource, line, el);
|
|
||||||
if (cl.contains('icon-pin')) return pinResource(resource, el);
|
|
||||||
if (cl.contains('icon-trash-empty')) return removeResource(resource, line);
|
|
||||||
});
|
|
||||||
|
|
||||||
body.addEventListener('change', function (ev) {
|
|
||||||
const el = ev.target,
|
|
||||||
cl = el.classList,
|
|
||||||
line = el.parentNode;
|
|
||||||
const resource = Resources.get(+line.dataset.id);
|
|
||||||
if (cl.contains('resourceName')) return changeName(resource, el.value, line);
|
|
||||||
if (cl.contains('resourceValue')) return changeValue(resource, el.value, line);
|
|
||||||
if (cl.contains('resourceChance')) return changeChance(resource, el.value, line);
|
|
||||||
});
|
|
||||||
|
|
||||||
function getBonusIcon(bonus) {
|
|
||||||
if (bonus === 'fleet') return `<span data-tip="Fleet bonus" class="icon-anchor"></span>`;
|
|
||||||
if (bonus === 'defence') return `<span data-tip="Defence bonus" class="icon-chess-rook"></span>`;
|
|
||||||
if (bonus === 'prestige') return `<span data-tip="Prestige bonus" class="icon-star"></span>`;
|
|
||||||
if (bonus === 'artillery') return `<span data-tip="Artillery bonus" class="icon-rocket"></span>`;
|
|
||||||
if (bonus === 'infantry') return `<span data-tip="Infantry bonus" class="icon-chess-pawn"></span>`;
|
|
||||||
if (bonus === 'population') return `<span data-tip="Population bonus" class="icon-male"></span>`;
|
|
||||||
if (bonus === 'archers') return `<span data-tip="Archers bonus" class="icon-dot-circled"></span>`;
|
|
||||||
if (bonus === 'cavalry') return `<span data-tip="Cavalry bonus" class="icon-chess-knight"></span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add line for each resource
|
|
||||||
function resourcesEditorAddLines() {
|
|
||||||
const addTitle = (string, max) => (string.length < max ? '' : `title="${string}"`);
|
|
||||||
let lines = '';
|
|
||||||
|
|
||||||
for (const r of pack.resources) {
|
|
||||||
const stroke = Resources.getStroke(r.color);
|
|
||||||
const model = r.model.replaceAll('_', ' ');
|
|
||||||
const bonusArray = Object.entries(r.bonus)
|
|
||||||
.map((e) => Array(e[1]).fill(e[0]))
|
|
||||||
.flat();
|
|
||||||
const bonusHTML = bonusArray.map((bonus) => getBonusIcon(bonus)).join('');
|
|
||||||
const bonusString = Object.entries(r.bonus)
|
|
||||||
.map((e) => e.join(': '))
|
|
||||||
.join('; ');
|
|
||||||
|
|
||||||
lines += `<div class="states resources"
|
|
||||||
data-id=${r.i} data-name="${r.name}" data-color="${r.color}"
|
|
||||||
data-category="${r.category}" data-chance="${r.chance}" data-bonus="${bonusString}"
|
|
||||||
data-value="${r.value}" data-model="${r.model}" data-cells="${r.cells}">
|
|
||||||
<svg data-tip="Resource icon. Click to change" width="2em" height="2em" class="resourceIcon">
|
|
||||||
<circle cx="50%" cy="50%" r="42%" fill="${r.color}" stroke="${stroke}"/>
|
|
||||||
<use href="#${r.icon}" x="10%" y="10%" width="80%" height="80%"/>
|
|
||||||
</svg>
|
|
||||||
<input data-tip="Resource name. Click and category to change" class="resourceName" value="${r.name}" autocorrect="off" spellcheck="false">
|
|
||||||
<div data-tip="Resource category. Select to change" class="resourceCategory">${r.category}</div>
|
|
||||||
<input data-tip="Resource generation chance in eligible cell. Click and type to change" class="resourceChance" value="${r.chance}" type="number" min=0 max=100 step=.1 />
|
|
||||||
<div data-tip="Number of cells with resource" class="resourceCells">${r.cells}</div>
|
|
||||||
|
|
||||||
<div data-tip="Resource spread model. Click to change" class="resourceModel hide" ${addTitle(model, 8)}">${model}</div>
|
|
||||||
<input data-tip="Resource basic value. Click and type to change" class="resourceValue hide" value="${r.value}" type="number" min=0 max=100 step=1 />
|
|
||||||
<div data-tip="Resource bonus. Click to change" class="resourceBonus hide" title="${bonusString}">${bonusHTML || "<span style='opacity:0'>place</span>"}</div>
|
|
||||||
|
|
||||||
<span data-tip="Toogle resource exclusive visibility (pin)" class="icon-pin inactive hide"></span>
|
|
||||||
<span data-tip="Remove resource" class="icon-trash-empty hide"></span>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
body.innerHTML = lines;
|
|
||||||
|
|
||||||
// update footer
|
|
||||||
document.getElementById('resourcesNumber').innerHTML = pack.resources.length;
|
|
||||||
|
|
||||||
// add listeners
|
|
||||||
body.querySelectorAll('div.states').forEach((el) => el.addEventListener('click', selectResourceOnLineClick));
|
|
||||||
|
|
||||||
if (body.dataset.type === 'percentage') {
|
|
||||||
body.dataset.type = 'absolute';
|
|
||||||
togglePercentageMode();
|
|
||||||
}
|
|
||||||
applySorting(resourcesHeader);
|
|
||||||
$('#resourcesEditor').dialog({width: fitContent()});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeCategory(resource, line, el) {
|
|
||||||
const categories = [...new Set(pack.resources.map((r) => r.category))].sort();
|
|
||||||
const categoryOptions = (category) => categories.map((c) => `<option ${c === category ? 'selected' : ''} value="${c}">${c}</option>`).join('');
|
|
||||||
|
|
||||||
alertMessage.innerHTML = `
|
|
||||||
<div style="margin-bottom:.2em" data-tip="Select category from the list">
|
|
||||||
<div style="display: inline-block; width: 9em">Select category:</div>
|
|
||||||
<select style="width: 9em" id="resouceCategorySelect">${categoryOptions(line.dataset.category)}</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-bottom:.2em" data-tip="Type new category name">
|
|
||||||
<div style="display: inline-block; width: 9em">Custom category:</div>
|
|
||||||
<input style="width: 9em" id="resouceCategoryAdd" placeholder="Category name" />
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
$('#alert').dialog({
|
|
||||||
resizable: false,
|
|
||||||
title: 'Change category',
|
|
||||||
buttons: {
|
|
||||||
Cancel: function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
},
|
|
||||||
Apply: function () {
|
|
||||||
applyChanges();
|
|
||||||
$(this).dialog('close');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function applyChanges() {
|
|
||||||
const custom = document.getElementById('resouceCategoryAdd').value;
|
|
||||||
const select = document.getElementById('resouceCategorySelect').value;
|
|
||||||
const category = custom ? capitalize(custom) : select;
|
|
||||||
resource.category = line.dataset.category = el.innerHTML = category;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeModel(resource, line, el) {
|
|
||||||
const model = line.dataset.model;
|
|
||||||
const modelOptions = Object.keys(models)
|
|
||||||
.sort()
|
|
||||||
.map((m) => `<option ${m === model ? 'selected' : ''} value="${m}">${m.replaceAll('_', ' ')}</option>`)
|
|
||||||
.join('');
|
|
||||||
const wikiURL = 'https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Resources:-spread-functions';
|
|
||||||
const onSelect = "resouceModelFunction.innerHTML = Resources.models[this.value] || ' '; resouceModelCustomName.value = ''; resouceModelCustomFunction.value = ''";
|
|
||||||
|
|
||||||
alertMessage.innerHTML = `
|
|
||||||
<fieldset data-tip="Select one of the predefined spread models from the list" style="border: 1px solid #999; margin-bottom: 1em">
|
|
||||||
<legend>Predefined models</legend>
|
|
||||||
<div style="margin-bottom:.2em">
|
|
||||||
<div style="display: inline-block; width: 6em">Name:</div>
|
|
||||||
<select onchange="${onSelect}" style="width: 18em" id="resouceModelSelect">
|
|
||||||
<option value=""><i>Custom</i></option>
|
|
||||||
${modelOptions}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-bottom:.2em">
|
|
||||||
<div style="display: inline-block; width: 6em">Function:</div>
|
|
||||||
<div id="resouceModelFunction" style="display: inline-block; width: 18em; font-family: monospace; border: 1px solid #ccc; padding: 3px; font-size: .95em;vertical-align: middle">
|
|
||||||
${models[model] || ' '}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset data-tip="Advanced option. Define custom spread model, click on 'Help' for details" style="border: 1px solid #999">
|
|
||||||
<legend>Custom model</legend>
|
|
||||||
<div style="margin-bottom:.2em">
|
|
||||||
<div style="display: inline-block; width: 6em">Name:</div>
|
|
||||||
<input style="width: 18em" id="resouceModelCustomName" value="${resource.custom ? resource.model : ''}" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div style="display: inline-block; width: 6em">Function:</div>
|
|
||||||
<input style="width: 18.75em; font-family: monospace; font-size: .95em" id="resouceModelCustomFunction" spellcheck="false" value="${resource.custom || ''}"/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div id="resourceModelMessage" style="color: #b20000; margin: .4em 1em 0"></div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
$('#alert').dialog({
|
|
||||||
resizable: false,
|
|
||||||
title: 'Change spread model',
|
|
||||||
buttons: {
|
|
||||||
Help: () => openURL(wikiURL),
|
|
||||||
Cancel: function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
},
|
|
||||||
Apply: function () {
|
|
||||||
applyChanges(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function applyChanges(dialog) {
|
|
||||||
const customName = document.getElementById('resouceModelCustomName').value;
|
|
||||||
const customFn = document.getElementById('resouceModelCustomFunction').value;
|
|
||||||
|
|
||||||
const message = document.getElementById('resourceModelMessage');
|
|
||||||
if (customName && !customFn) return (message.innerHTML = 'Error. Custom model function is required');
|
|
||||||
if (!customName && customFn) return (message.innerHTML = 'Error. Custom model name is required');
|
|
||||||
message.innerHTML = '';
|
|
||||||
|
|
||||||
if (customName && customFn) {
|
|
||||||
try {
|
|
||||||
const allMethods = '{' + Object.keys(Resources.methods).join(', ') + '}';
|
|
||||||
const fn = new Function(allMethods, 'return ' + customFn);
|
|
||||||
fn({...Resources.methods});
|
|
||||||
} catch (err) {
|
|
||||||
message.innerHTML = 'Error. ' + err.message || err;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resource.model = line.dataset.model = el.innerHTML = customName;
|
|
||||||
el.setAttribute('title', customName.length > 7 ? customName : '');
|
|
||||||
resource.custom = customFn;
|
|
||||||
$(dialog).dialog('close');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = document.getElementById('resouceModelSelect').value;
|
|
||||||
if (!model) return (message.innerHTML = 'Error. Model is not set');
|
|
||||||
|
|
||||||
resource.model = line.dataset.model = el.innerHTML = model;
|
|
||||||
el.setAttribute('title', model.length > 7 ? model : '');
|
|
||||||
$(dialog).dialog('close');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeBonus(resource, line, el) {
|
|
||||||
const bonuses = [...new Set(pack.resources.map((r) => Object.keys(r.bonus)).flat())].sort();
|
|
||||||
const inputs = bonuses.map(
|
|
||||||
(bonus) => `<div style="margin-bottom:.2em">
|
|
||||||
${getBonusIcon(bonus)}
|
|
||||||
<div style="display: inline-block; width: 8em">${capitalize(bonus)}</div>
|
|
||||||
<input id="resourceBonus_${bonus}" style="width: 4.1em" type="number" step="1" min="0" max="9" value="${resource.bonus[bonus] || 0}" />
|
|
||||||
</div>`
|
|
||||||
);
|
|
||||||
|
|
||||||
alertMessage.innerHTML = inputs.join('');
|
|
||||||
$('#alert').dialog({
|
|
||||||
resizable: false,
|
|
||||||
title: 'Change bonus',
|
|
||||||
buttons: {
|
|
||||||
Cancel: function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
},
|
|
||||||
Apply: function () {
|
|
||||||
applyChanges();
|
|
||||||
$(this).dialog('close');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function applyChanges() {
|
|
||||||
const bonusObj = {};
|
|
||||||
bonuses.forEach((bonus) => {
|
|
||||||
const el = document.getElementById('resourceBonus_' + bonus);
|
|
||||||
const value = parseInt(el.value);
|
|
||||||
if (isNaN(value) || !value) return;
|
|
||||||
bonusObj[bonus] = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
const bonusArray = Object.entries(bonusObj).map(e => Array(e[1]).fill(e[0])).flat(); //prettier-ignore
|
|
||||||
const bonusHTML = bonusArray.map((bonus) => getBonusIcon(bonus)).join('');
|
|
||||||
const bonusString = Object.entries(bonusObj).map((e) => e.join(': ')).join('; '); //prettier-ignore
|
|
||||||
|
|
||||||
resource.bonus = bonusObj;
|
|
||||||
el.innerHTML = bonusHTML || "<span style='opacity:0'>place</span>";
|
|
||||||
line.dataset.bonus = bonusString;
|
|
||||||
el.setAttribute('title', bonusString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeName(resource, name, line) {
|
|
||||||
resource.name = line.dataset.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeValue(resource, value, line) {
|
|
||||||
resource.value = line.dataset.value = +value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeChance(resource, chance, line) {
|
|
||||||
resource.chance = line.dataset.chance = +chance;
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeIcon(resource, line, el) {
|
|
||||||
const standardIcons = Array.from(document.getElementById('resource-icons').querySelectorAll('symbol')).map((el) => el.id);
|
|
||||||
const standardIconsOptions = standardIcons.map((icon) => `<option value=${icon}>${icon}</option>`);
|
|
||||||
|
|
||||||
const customIconsEl = document.getElementById('defs-icons');
|
|
||||||
const customIcons = customIconsEl ? Array.from(document.getElementById('defs-icons').querySelectorAll('svg')).map((el) => el.id) : [];
|
|
||||||
const customIconsOptions = customIcons.map((icon) => `<option value=${icon}>${icon}</option>`);
|
|
||||||
|
|
||||||
const select = document.getElementById('resourceSelectIcon');
|
|
||||||
select.innerHTML = standardIconsOptions + customIconsOptions;
|
|
||||||
select.value = resource.icon;
|
|
||||||
|
|
||||||
const preview = document.getElementById('resourceIconPreview');
|
|
||||||
preview.setAttribute('href', '#' + resource.icon);
|
|
||||||
|
|
||||||
const viewBoxSection = document.getElementById('resourceIconEditorViewboxFields');
|
|
||||||
viewBoxSection.style.display = 'none';
|
|
||||||
|
|
||||||
$('#resourceIconEditor').dialog({
|
|
||||||
resizable: false,
|
|
||||||
title: 'Change Icon',
|
|
||||||
buttons: {
|
|
||||||
Cancel: function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
},
|
|
||||||
'Change color': () => changeColor(resource, line, el),
|
|
||||||
Apply: function () {
|
|
||||||
$(this).dialog('close');
|
|
||||||
|
|
||||||
resource.icon = select.value;
|
|
||||||
line.querySelector('svg.resourceIcon > use').setAttribute('href', '#' + select.value);
|
|
||||||
drawResources();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
position: {my: 'center bottom', at: 'center', of: 'svg'}
|
|
||||||
});
|
|
||||||
|
|
||||||
const uploadTo = document.getElementById('defs-icons');
|
|
||||||
const onUpload = (type, id) => {
|
|
||||||
preview.setAttribute('href', '#' + id);
|
|
||||||
select.innerHTML += `<option value=${id}>${id}</option>`;
|
|
||||||
select.value = id;
|
|
||||||
|
|
||||||
if (type === 'image') return;
|
|
||||||
|
|
||||||
// let user set viewBox for svg image
|
|
||||||
const el = document.getElementById(id);
|
|
||||||
viewBoxSection.style.display = 'block';
|
|
||||||
const viewBoxAttr = el.getAttribute('viewBox');
|
|
||||||
const initialViewBox = viewBoxAttr ? viewBoxAttr.split(' ') : [0, 0, 200, 200];
|
|
||||||
const inputs = viewBoxSection.querySelectorAll('input');
|
|
||||||
const changeInput = () => {
|
|
||||||
const viewBox = Array.from(inputs)
|
|
||||||
.map((input) => input.value)
|
|
||||||
.join(' ');
|
|
||||||
el.setAttribute('viewBox', viewBox);
|
|
||||||
};
|
|
||||||
inputs.forEach((input, i) => {
|
|
||||||
input.value = initialViewBox[i];
|
|
||||||
input.onchange = changeInput;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// add listeners
|
|
||||||
select.onchange = () => preview.setAttribute('href', '#' + select.value);
|
|
||||||
document.getElementById('resourceUploadIconRaster').onclick = () => imageToLoad.click();
|
|
||||||
document.getElementById('resourceUploadIconVector').onclick = () => svgToLoad.click();
|
|
||||||
document.getElementById('imageToLoad').onchange = () => uploadImage('image', uploadTo, onUpload);
|
|
||||||
document.getElementById('svgToLoad').onchange = () => uploadImage('svg', uploadTo, onUpload);
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploadImage(type, uploadTo, callback) {
|
|
||||||
const input = type === 'image' ? document.getElementById('imageToLoad') : document.getElementById('svgToLoad');
|
|
||||||
const file = input.files[0];
|
|
||||||
input.value = '';
|
|
||||||
|
|
||||||
if (file.size > 200000) return tip(`File is too big, please optimize file size up to 200kB and re-upload. Recommended size is 48x48 px and up to 10kB`, true, 'error', 5000);
|
|
||||||
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = function (readerEvent) {
|
|
||||||
const result = readerEvent.target.result;
|
|
||||||
const id = 'resource-custom-' + Math.random().toString(36).slice(-6);
|
|
||||||
|
|
||||||
if (type === 'image') {
|
|
||||||
const svg = `<svg id="${id}" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><image x="0" y="0" width="200" height="200" href="${result}"/></svg>`;
|
|
||||||
uploadTo.insertAdjacentHTML('beforeend', svg);
|
|
||||||
} else {
|
|
||||||
const el = document.createElement('html');
|
|
||||||
el.innerHTML = result;
|
|
||||||
|
|
||||||
// remove sodipodi and inkscape attributes
|
|
||||||
el.querySelectorAll('*').forEach((el) => {
|
|
||||||
const attributes = el.getAttributeNames();
|
|
||||||
attributes.forEach((attr) => {
|
|
||||||
if (attr.includes('inkscape') || attr.includes('sodipodi')) el.removeAttribute(attr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove all text if source is Noun project (to make it usable)
|
|
||||||
if (result.includes('from the Noun Project')) el.querySelectorAll('text').forEach((textEl) => textEl.remove());
|
|
||||||
|
|
||||||
const svg = el.querySelector('svg');
|
|
||||||
if (!svg) return tip("The file should be prepated for load to FMG. If you don't know why it's happening, try to upload the raster image", false, 'error');
|
|
||||||
|
|
||||||
const icon = uploadTo.appendChild(svg);
|
|
||||||
icon.id = id;
|
|
||||||
icon.setAttribute('width', 200);
|
|
||||||
icon.setAttribute('height', 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(type, id);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type === 'image') reader.readAsDataURL(file);
|
|
||||||
else reader.readAsText(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeColor(resource, line, el) {
|
|
||||||
const circle = el.querySelector('circle');
|
|
||||||
|
|
||||||
const callback = (fill) => {
|
|
||||||
const stroke = Resources.getStroke(fill);
|
|
||||||
circle.setAttribute('fill', fill);
|
|
||||||
circle.setAttribute('stroke', stroke);
|
|
||||||
resource.color = fill;
|
|
||||||
resource.stroke = stroke;
|
|
||||||
goods.selectAll(`circle[data-i='${resource.i}']`).attr('fill', fill).attr('stroke', stroke);
|
|
||||||
line.dataset.color = fill;
|
|
||||||
};
|
|
||||||
|
|
||||||
openPicker(resource.color, callback, {allowHatching: false});
|
|
||||||
}
|
|
||||||
|
|
||||||
function regenerateCurrentResources() {
|
|
||||||
const message = 'Are you sure you want to regenerate resources? <br>This action cannot be reverted';
|
|
||||||
confirmationDialog({title: 'Regenerate resources', message, confirm: 'Regenerate', onConfirm: regenerateResources});
|
|
||||||
}
|
|
||||||
|
|
||||||
function resourcesRestoreDefaults() {
|
|
||||||
const message = 'Are you sure you want to restore default resources? <br>This action cannot be reverted';
|
|
||||||
const onConfirm = () => {
|
|
||||||
delete pack.resources;
|
|
||||||
regenerateResources();
|
|
||||||
};
|
|
||||||
confirmationDialog({title: 'Restore default resources', message, confirm: 'Restore', onConfirm});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleLegend() {
|
|
||||||
if (legend.selectAll('*').size()) {
|
|
||||||
clearLegend();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = pack.resources
|
|
||||||
.filter((r) => r.i && r.cells)
|
|
||||||
.sort((a, b) => b.cells - a.cells)
|
|
||||||
.map((r) => [r.i, r.color, r.name]);
|
|
||||||
drawLegend('Resources', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function togglePercentageMode() {
|
|
||||||
if (body.dataset.type === 'absolute') {
|
|
||||||
body.dataset.type = 'percentage';
|
|
||||||
const totalCells = pack.cells.resource.filter((r) => r !== 0).length;
|
|
||||||
|
|
||||||
body.querySelectorAll(':scope > div').forEach(function (el) {
|
|
||||||
el.querySelector('.cells').innerHTML = rn((+el.dataset.cells / totalCells) * 100) + '%';
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
body.dataset.type = 'absolute';
|
|
||||||
resourcesEditorAddLines();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function enterResourceAssignMode() {
|
|
||||||
if (this.classList.contains('pressed')) return exitResourceAssignMode();
|
|
||||||
customization = 14;
|
|
||||||
this.classList.add('pressed');
|
|
||||||
if (!layerIsOn('toggleResources')) toggleResources();
|
|
||||||
if (!layerIsOn('toggleCells')) {
|
|
||||||
const toggler = document.getElementById('toggleCells');
|
|
||||||
toggler.dataset.forced = true;
|
|
||||||
toggleCells();
|
|
||||||
}
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById('resourcesEditor')
|
|
||||||
.querySelectorAll('.hide')
|
|
||||||
.forEach((el) => el.classList.add('hidden'));
|
|
||||||
document.getElementById('resourcesFooter').style.display = 'none';
|
|
||||||
body.querySelectorAll('.resourceName, .resourceCategory, .resourceChance, .resourceCells, svg').forEach((e) => (e.style.pointerEvents = 'none'));
|
|
||||||
$('#resourcesEditor').dialog({position: {my: 'right top', at: 'right-10 top+10', of: 'svg', collision: 'fit'}});
|
|
||||||
|
|
||||||
tip('Select resource line in editor, click on cells to remove or add a resource', true);
|
|
||||||
viewbox.on('click', changeResourceOnCellClick);
|
|
||||||
|
|
||||||
body.querySelector('div').classList.add('selected');
|
|
||||||
|
|
||||||
const someArePinned = pack.resources.some((resource) => resource.pinned);
|
|
||||||
if (someArePinned) unpinAllResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectResourceOnLineClick() {
|
|
||||||
if (customization !== 14) return;
|
|
||||||
//if (this.parentNode.id !== "statesBodySection") return;
|
|
||||||
body.querySelector('div.selected').classList.remove('selected');
|
|
||||||
this.classList.add('selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeResourceOnCellClick() {
|
|
||||||
const point = d3.mouse(this);
|
|
||||||
const i = findCell(point[0], point[1]);
|
|
||||||
const selected = body.querySelector('div.selected');
|
|
||||||
if (!selected) return;
|
|
||||||
|
|
||||||
if (pack.cells.resource[i]) {
|
|
||||||
const resourceToRemove = Resources.get(pack.cells.resource[i]);
|
|
||||||
if (resourceToRemove) resourceToRemove.cells -= 1;
|
|
||||||
body.querySelector("div.states[data-id='" + resourceToRemove.i + "'] > .resourceCells").innerHTML = resourceToRemove.cells;
|
|
||||||
pack.cells.resource[i] = 0;
|
|
||||||
} else {
|
|
||||||
const resourceId = +selected.dataset.id;
|
|
||||||
const resource = Resources.get(resourceId);
|
|
||||||
resource.cells += 1;
|
|
||||||
body.querySelector("div.states[data-id='" + resourceId + "'] > .resourceCells").innerHTML = resource.cells;
|
|
||||||
pack.cells.resource[i] = resourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
goods.selectAll('*').remove();
|
|
||||||
drawResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
function exitResourceAssignMode(close) {
|
|
||||||
customization = 0;
|
|
||||||
document.getElementById('resourcesAssign').classList.remove('pressed');
|
|
||||||
|
|
||||||
if (layerIsOn('toggleCells')) {
|
|
||||||
const toggler = document.getElementById('toggleCells');
|
|
||||||
if (toggler.dataset.forced) toggleCells();
|
|
||||||
delete toggler.dataset.forced;
|
|
||||||
}
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById('resourcesEditor')
|
|
||||||
.querySelectorAll('.hide')
|
|
||||||
.forEach((el) => el.classList.remove('hidden'));
|
|
||||||
document.getElementById('resourcesFooter').style.display = 'block';
|
|
||||||
body.querySelectorAll('.resourceName, .resourceCategory, .resourceChance, .resourceCells, svg').forEach((e) => delete e.style.pointerEvents);
|
|
||||||
!close && $('#resourcesEditor').dialog({position: {my: 'right top', at: 'right-10 top+10', of: 'svg', collision: 'fit'}});
|
|
||||||
|
|
||||||
restoreDefaultEvents();
|
|
||||||
clearMainTip();
|
|
||||||
const selected = body.querySelector('div.selected');
|
|
||||||
if (selected) selected.classList.remove('selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
function resourceAdd() {
|
|
||||||
if (pack.resources.length >= 256) return tip('Maximum number of resources is reached', false, 'error');
|
|
||||||
|
|
||||||
let i = last(pack.resources).i;
|
|
||||||
while (Resources.get(i)) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
const resource = {i, name: 'Resource' + i, category: 'Unknown', icon: 'resource-unknown', color: '#ff5959', value: 1, chance: 10, model: 'habitability', bonus: {population: 1}, cells: 0};
|
|
||||||
pack.resources.push(resource);
|
|
||||||
tip('Resource is added', false, 'success', 3000);
|
|
||||||
resourcesEditorAddLines();
|
|
||||||
}
|
|
||||||
|
|
||||||
function downloadResourcesData() {
|
|
||||||
let data = 'Id,Resource,Color,Category,Value,Bonus,Chance,Model,Cells\n'; // headers
|
|
||||||
|
|
||||||
body.querySelectorAll(':scope > div').forEach(function (el) {
|
|
||||||
data += el.dataset.id + ',';
|
|
||||||
data += el.dataset.name + ',';
|
|
||||||
data += el.dataset.color + ',';
|
|
||||||
data += el.dataset.category + ',';
|
|
||||||
data += el.dataset.value + ',';
|
|
||||||
data += el.dataset.bonus + ',';
|
|
||||||
data += el.dataset.chance + ',';
|
|
||||||
data += el.dataset.model + ',';
|
|
||||||
data += el.dataset.cells + '\n';
|
|
||||||
});
|
|
||||||
|
|
||||||
const name = getFileName('Resources') + '.csv';
|
|
||||||
downloadFile(data, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pinResource(resource, el) {
|
|
||||||
const pin = el.classList.contains('inactive');
|
|
||||||
el.classList.toggle('inactive');
|
|
||||||
|
|
||||||
if (pin) resource.pinned = pin;
|
|
||||||
else delete resource.pinned;
|
|
||||||
|
|
||||||
goods.selectAll('*').remove();
|
|
||||||
drawResources();
|
|
||||||
|
|
||||||
// manage top unpin all button state
|
|
||||||
const someArePinned = pack.resources.some((resource) => resource.pinned);
|
|
||||||
const unpinAll = document.getElementById('resourcesUnpinAll');
|
|
||||||
someArePinned ? unpinAll.classList.remove('hidden') : unpinAll.classList.add('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
function unpinAllResources() {
|
|
||||||
pack.resources.forEach((resource) => delete resource.pinned);
|
|
||||||
goods.selectAll('*').remove();
|
|
||||||
drawResources();
|
|
||||||
|
|
||||||
document.getElementById('resourcesUnpinAll').classList.add('hidden');
|
|
||||||
body.querySelectorAll(':scope > div > span.icon-pin').forEach((el) => el.classList.add('inactive'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeResource(res, line) {
|
|
||||||
if (customization) return;
|
|
||||||
|
|
||||||
const message = 'Are you sure you want to remove the resource? <br>This action cannot be reverted';
|
|
||||||
const onConfirm = () => {
|
|
||||||
for (const i of pack.cells.i) {
|
|
||||||
if (pack.cells.resource[i] === res.i) {
|
|
||||||
pack.cells.resource[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pack.resources = pack.resources.filter((resource) => resource.i !== res.i);
|
|
||||||
line.remove();
|
|
||||||
|
|
||||||
goods.selectAll('*').remove();
|
|
||||||
drawResources();
|
|
||||||
};
|
|
||||||
confirmationDialog({title: 'Remove resource', message, confirm: 'Remove', onConfirm});
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeResourcesEditor() {
|
|
||||||
if (customization === 14) exitResourceAssignMode('close');
|
|
||||||
unpinAllResources();
|
|
||||||
body.innerHTML = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue