From dd1510e4ff8aa506c688e2db94b1acbdae5ad760 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 17 Sep 2019 22:25:19 +0300 Subject: [PATCH 01/18] 1.0.40 --- index.html | 3 +- modules/save-and-load.js | 125 +++++++++++++++++++------------ modules/ui/burgs-editor.js | 130 ++++++++++++++++++++++++++++++++- modules/ui/general.js | 45 +++++++++++- modules/ui/heightmap-editor.js | 4 +- modules/ui/provinces-editor.js | 12 +-- modules/ui/states-editor.js | 2 +- modules/utils.js | 5 ++ 8 files changed, 265 insertions(+), 61 deletions(-) diff --git a/index.html b/index.html index d9b6a5e7..1eca7f3a 100644 --- a/index.html +++ b/index.html @@ -1823,7 +1823,7 @@
-

Fantasy Map Generator is a free open source tool which procedurally generates fantasy maps. You may use auto-generated maps as they are, edit them or even create a new map from scratch. Check out the quick start tutorial and project wiki for guidance.

+

Fantasy Map Generator is a free open source tool which procedurally generates fantasy maps. You may use auto-generated maps as they are, edit them or even create a new map from scratch. Check out the quick start tutorial and Q&A for guidance.

Join our Discord server and Reddit community to ask questions, get help and share created maps. You may support the project on Patreon.

The project is under active development. For older versions see the changelog. To track the development progress see the devboard. Please report bugs here. You can also contact me directly via email.

A special thanks to all supporters!

@@ -2626,6 +2626,7 @@
+ diff --git a/modules/save-and-load.js b/modules/save-and-load.js index a7d0f4f6..0e983662 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -162,11 +162,11 @@ function getMapData() { const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator"; const params = [version, license, dateString, seed, graphWidth, graphHeight].join("|"); - const options = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value, + const options = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value, heightUnit.value, heightExponentInput.value, temperatureScale.value, - barSize.value, barLabel.value, barBackOpacity.value, barBackColor.value, + barSize.value, barLabel.value, barBackOpacity.value, barBackColor.value, barPosX.value, barPosY.value, populationRate.value, urbanization.value, - mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value, + mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value, temperaturePoleOutput.value, precOutput.value, JSON.stringify(winds), mapName.value].join("|"); const coords = JSON.stringify(mapCoordinates); @@ -240,11 +240,57 @@ function saveGeoJSON() { Cells: saveGeoJSON_Cells, Routes: saveGeoJSON_Roads, Rivers: saveGeoJSON_Rivers, + Markers: saveGeoJSON_Markers, Close: function() {$(this).dialog("close");} } }); } + +function saveGeoJSON_Cells() { + let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; + const cells = pack.cells, v = pack.vertices; + + cells.i.forEach(i => { + data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [["; + cells.v[i].forEach(n => { + let x = mapCoordinates.lonW + (v.p[n][0] / graphWidth) * mapCoordinates.lonT; + let y = mapCoordinates.latN - (v.p[n][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise + data += "["+x+","+y+"],"; + }); + // close the ring + let x = mapCoordinates.lonW + (v.p[cells.v[i][0]][0] / graphWidth) * mapCoordinates.lonT; + let y = mapCoordinates.latN - (v.p[cells.v[i][0]][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise + data += "["+x+","+y+"]"; + data += "]] },\n \"properties\": {\n"; + + let height = parseInt(getFriendlyHeight([cells.p[i][0],cells.p[i][1]])); + + data += " \"id\": \""+i+"\",\n"; + data += " \"height\": \""+height+"\",\n"; + data += " \"biome\": \""+cells.biome[i]+"\",\n"; + data += " \"type\": \""+pack.features[cells.f[i]].type+"\",\n"; + data += " \"population\": \""+getFriendlyPopulation(i)+"\",\n"; + data += " \"state\": \""+cells.state[i]+"\",\n"; + data += " \"province\": \""+cells.province[i]+"\",\n"; + data += " \"culture\": \""+cells.culture[i]+"\",\n"; + data += " \"religion\": \""+cells.religion[i]+"\"\n"; + data +=" }\n},\n"; + }); + + data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma + data += "]}"; + + const dataBlob = new Blob([data], {type: "application/json"}); + const url = window.URL.createObjectURL(dataBlob); + const link = document.createElement("a"); + document.body.appendChild(link); + link.download = getFileName("Cells") + ".geojson"; + link.href = url; + link.click(); + window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000); +} + function saveGeoJSON_Roads() { let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; @@ -296,6 +342,34 @@ function saveGeoJSON_Rivers() { window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000); } +function saveGeoJSON_Markers() { + + let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; + + markers._groups[0][0].childNodes.forEach(n => { + let x = mapCoordinates.lonW + (n.dataset.x / graphWidth) * mapCoordinates.lonT; + let y = mapCoordinates.latN - (n.dataset.y / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise + + data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Point\", \"coordinates\": ["+x+", "+y+"]"; + data += " },\n \"properties\": {\n"; + data += " \"id\": \""+n.id+"\",\n"; + data += " \"type\": \""+n.dataset.id.substring(8)+"\"\n"; + data +=" }\n},\n"; + + }); + data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma + data += "]}"; + + const dataBlob = new Blob([data], {type: "application/json"}); + const url = window.URL.createObjectURL(dataBlob); + const link = document.createElement("a"); + document.body.appendChild(link); + link.download = getFileName("Markers") + ".geojson"; + link.href = url; + link.click(); + window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000); +} + function getRoadPoints(node) { let points = []; const l = node.getTotalLength(); @@ -413,49 +487,6 @@ function getFileName(dataType) { return name + " " + type + day + " " + time; } -function saveGeoJSON_Cells() { - let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n"; - const cells = pack.cells, v = pack.vertices; - - cells.i.forEach(i => { - data += "{\n \"type\": \"Feature\",\n \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [["; - cells.v[i].forEach(n => { - let x = mapCoordinates.lonW + (v.p[n][0] / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (v.p[n][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - data += "["+x+","+y+"],"; - }); - // close the ring - let x = mapCoordinates.lonW + (v.p[cells.v[i][0]][0] / graphWidth) * mapCoordinates.lonT; - let y = mapCoordinates.latN - (v.p[cells.v[i][0]][1] / graphHeight) * mapCoordinates.latT; // this is inverted in QGIS otherwise - data += "["+x+","+y+"]"; - data += "]] },\n \"properties\": {\n"; - - let height = parseInt(getFriendlyHeight(cells.h[i])); - - data += " \"id\": \""+i+"\",\n"; - data += " \"height\": \""+height+"\",\n"; - data += " \"biome\": \""+cells.biome[i]+"\",\n"; - data += " \"population\": \""+cells.pop[i]+"\",\n"; - data += " \"state\": \""+cells.state[i]+"\",\n"; - data += " \"province\": \""+cells.province[i]+"\",\n"; - data += " \"culture\": \""+cells.culture[i]+"\",\n"; - data += " \"religion\": \""+cells.religion[i]+"\"\n"; - data +=" }\n},\n"; - }); - - data = data.substring(0, data.length - 2)+"\n"; // remove trailing comma - data += "]}"; - - const dataBlob = new Blob([data], {type: "application/json"}); - const url = window.URL.createObjectURL(dataBlob); - const link = document.createElement("a"); - document.body.appendChild(link); - link.download = getFileName("Cells") + ".geojson"; - link.href = url; - link.click(); - window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000); -} - function uploadFile(file, callback) { uploadFile.timeStart = performance.now(); @@ -822,4 +853,4 @@ function parseLoadedData(data) { }); } -} \ No newline at end of file +} diff --git a/modules/ui/burgs-editor.js b/modules/ui/burgs-editor.js index 22c3bf37..bfbdcfa9 100644 --- a/modules/ui/burgs-editor.js +++ b/modules/ui/burgs-editor.js @@ -20,6 +20,7 @@ function editBurgs() { // add listeners document.getElementById("burgsEditorRefresh").addEventListener("click", refreshBurgsEditor); + document.getElementById("burgsChart").addEventListener("click", showBurgsChart); document.getElementById("burgsFilterState").addEventListener("change", burgsEditorAddLines); document.getElementById("burgsFilterCulture").addEventListener("change", burgsEditorAddLines); document.getElementById("regenerateBurgNames").addEventListener("click", regenerateNames); @@ -250,6 +251,133 @@ function editBurgs() { if (addNewBurg.classList.contains("pressed")) addNewBurg.classList.remove("pressed"); } + function showBurgsChart() { + // build hierarchy tree + const states = pack.states.map(s => { + const color = s.color ? s.color : "#ccc"; + const name = s.fullName ? s.fullName : s.name; + return {id:s.i, state: s.i ? 0 : null, color, name} + }); + const burgs = pack.burgs.filter(b => b.i && !b.removed).map(b => { + const id = b.i+states.length-1; + const population = b.population; + const capital = b.capital; + const province = pack.cells.province[b.cell]; + const parent = province ? province + states.length-1 : b.state; + return {id, i:b.i, state:b.state, culture:b.culture, province, parent, name:b.name, population, capital, x:b.x, y:b.y} + }); + const data = states.concat(burgs); + + const root = d3.stratify().parentId(d => d.state)(data) + .sum(d => d.population).sort((a, b) => b.value - a.value); + + const width = 150 + 200 * uiSizeOutput.value, height = 150 + 200 * uiSizeOutput.value; + const margin = {top: 0, right: -50, bottom: -10, left: -50}; + const w = width - margin.left - margin.right; + const h = height - margin.top - margin.bottom; + const treeLayout = d3.pack().size([w, h]).padding(3); + + // prepare svg + alertMessage.innerHTML = ``; + alertMessage.innerHTML += `
`; + const svg = d3.select("#alertMessage").insert("svg", "#burgsInfo").attr("id", "burgsTree") + .attr("width", width).attr("height", height-10).attr("stroke-width", 2); + const graph = svg.append("g").attr("transform", `translate(-50, -10)`); + document.getElementById("burgsTreeType").addEventListener("change", updateChart); + + treeLayout(root); + + const node = graph.selectAll("circle").data(root.leaves()) + .join("circle").attr("data-id", d => d.data.i) + .attr("r", d => d.r).attr("fill", d => d.parent.data.color) + .attr("cx", d => d.x).attr("cy", d => d.y) + .on("mouseenter", d => showInfo(event, d)) + .on("mouseleave", d => hideInfo(event, d)) + .on("click", d => zoomTo(d.data.x, d.data.y, 8, 2000)); + + function showInfo(ev, d) { + d3.select(ev.target).transition().duration(1500).attr("stroke", "#c13119"); + const name = d.data.name; + const parent = d.parent.data.name; + const population = si(d.value * populationRate.value * urbanization.value); + + burgsInfo.innerHTML = `${name}. ${parent}. Population: ${population}`; + burgHighlightOn(ev); + tip("Click to zoom into view"); + } + + function hideInfo(ev) { + burgHighlightOff(ev); + if (!document.getElementById("burgsInfo")) return; + burgsInfo.innerHTML = "‍"; + d3.select(ev.target).transition().attr("stroke", "null"); + tip(""); + } + + function updateChart() { + const getStatesData = () => pack.states.map(s => { + const color = s.color ? s.color : "#ccc"; + const name = s.fullName ? s.fullName : s.name; + return {id:s.i, state: s.i ? 0 : null, color, name} + }); + + const getCulturesData = () => pack.cultures.map(c => { + const color = c.color ? c.color : "#ccc"; + return {id:c.i, culture: c.i ? 0 : null, color, name:c.name} + }); + + const getParentData = () => { + const states = pack.states.map(s => { + const color = s.color ? s.color : "#ccc"; + const name = s.fullName ? s.fullName : s.name; + return {id:s.i, parent: s.i ? 0 : null, color, name} + }); + const provinces = pack.provinces.filter(p => p.i && !p.removed).map(p => { + return {id:p.i + states.length-1, parent: p.state, color:p.color, name:p.fullName} + }); + return states.concat(provinces); + } + + const getProvincesData = () => pack.provinces.map(p => { + const color = p.color ? p.color : "#ccc"; + const name = p.fullName ? p.fullName : p.name; + return {id:p.i ? p.i : 0, province: p.i ? 0 : null, color, name} + }); + + const value = d => { + if (this.value === "states") return d.state; + if (this.value === "cultures") return d.culture; + if (this.value === "parent") return d.parent; + if (this.value === "provinces") return d.province; + } + + const base = this.value === "states" ? getStatesData() + : this.value === "cultures" ? getCulturesData() + : this.value === "parent" ? getParentData() : getProvincesData(); + burgs.forEach(b => b.id = b.i+base.length-1); + + const data = base.concat(burgs); + + const root = d3.stratify().parentId(d => value(d))(data) + .sum(d => d.population).sort((a, b) => b.value - a.value); + + node.data(treeLayout(root).leaves()).transition().duration(2000) + .attr("data-id", d => d.data.i).attr("fill", d => d.parent.data.color) + .attr("cx", d => d.x).attr("cy", d => d.y).attr("r", d => d.r); + } + + $("#alert").dialog({ + title: "Burgs bubble chart", width: fitContent(), + position: {my: "left bottom", at: "left+10 bottom-10", of: "svg"}, buttons: {}, + close: () => {alertMessage.innerHTML = "";} + }); + + } + function downloadBurgsData() { let data = "Id,Burg,Province,State,Culture,Religion,Population,Longitude,Latitude,Elevation ("+heightUnit.value+"),Capital,Port\n"; // headers const valid = pack.burgs.filter(b => b.i && !b.removed); // all valid burgs @@ -259,7 +387,7 @@ function editBurgs() { data += b.name + ","; const province = pack.cells.province[b.cell]; data += province ? pack.provinces[province].fullName + "," : ","; - data += b.state ? pack.states[b.state].fullName : pack.states[b.state].name + ","; + data += b.state ? pack.states[b.state].fullName +"," : pack.states[b.state].name + ","; data += pack.cultures[b.culture].name + ","; data += pack.religions[pack.cells.religion[b.cell]].name + ","; data += rn(b.population * populationRate.value * urbanization.value) + ","; diff --git a/modules/ui/general.js b/modules/ui/general.js index 95f1d8c7..00e8aa27 100644 --- a/modules/ui/general.js +++ b/modules/ui/general.js @@ -229,6 +229,42 @@ function applyOption(select, option) { select.value = option; } +// show info about the generator in a popup +function showInfo() { + const Discord = link("https://discordapp.com/invite/X7E84HU", "Discord"); + const Reddit = link("https://www.reddit.com/r/FantasyMapGenerator", "Reddit") + const Patreon = link("https://www.patreon.com/azgaar", "Patreon"); + const Trello = link("https://trello.com/b/7x832DG4/fantasy-map-generator", "Trello"); + + const QuickStart = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Quick-Start-Tutorial", "Quick start tutorial"); + const QAA = link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Q&A", "Q&A page"); + + alertMessage.innerHTML = ` + Fantasy Map Generator (FMG) is an open-source application, it means the code is published an anyone can use it. + In case of FMG is also means that you own all created maps and can use them as you wish, you can even sell them. + +

The development is supported by community, you can donate on ${Patreon}. + You can also help creating overviews, tutorials and spreding the word about the Generator.

+ +

The best way to get help is to contact the community on ${Discord} and ${Reddit}. + Before asking questions, please check out the ${QuickStart} and the ${QAA}.

+ +

You can track the development process on ${Trello}.

+ + Links: +
    +
  • ${link("https://github.com/Azgaar/Fantasy-Map-Generator", "GitHub repository")}
  • +
  • ${link("https://github.com/Azgaar/Fantasy-Map-Generator/blob/master/LICENSE", "License")}
  • +
  • ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog", "Changelog")}
  • +
  • ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys", "Hotkeys")}
  • +
`; + + $("#alert").dialog({resizable: false, title: document.title, width: "28em", + buttons: {OK: function() {$(this).dialog("close");}}, + position: {my: "center", at: "center", of: "svg"} + }); +} + // prevent default browser behavior for FMG-used hotkeys document.addEventListener("keydown", event => { if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab @@ -242,13 +278,14 @@ document.addEventListener("keyup", event => { event.stopPropagation(); const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey, meta = event.metaKey; - if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs - else if (key === 9) toggleOptions(event); // Tab to toggle options - + if (key === 112) showInfo(); // "F1" to show info else if (key === 113) regeneratePrompt(); // "F2" for new map - else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element + else if (key === 113) regeneratePrompt(); // "F2" for a new map else if (key === 117) quickSave(); // "F6" for quick save else if (key === 120) quickLoad(); // "F9" for quick load + else if (key === 9) toggleOptions(event); // Tab to toggle options + else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs + else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element 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 diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 67116613..8cee6258 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -11,8 +11,8 @@ function editHeightmap() {

If you need to change the coastline and keep the data, you may try the risk edit option. The data will be restored as much as possible, but the coastline change can cause unexpected fluctuations and errors.

-

Check out wiki for guidance.

- +

Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization", "wiki")} for guidance.

+

Please save the map before edditing the heightmap!

`; $("#alert").dialog({resizable: false, title: "Edit Heightmap", width: "28em", diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index 1b927509..b54ff395 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -286,8 +286,10 @@ function editProvinces() { const states = pack.states.map(s => { return {id:s.i, state: s.i?0:null, color: s.i && s.color[0] === "#" ? d3.color(s.color).darker() : "#666"} }); - const provinces = pack.provinces.filter(p => p.i && !p.removed); - provinces.forEach(p => p.id = p.i + states.length - 1); + const provinces = pack.provinces.filter(p => p.i && !p.removed).map(p => { + return {id:p.i+states.length-1, i:p.i, state:p.state, color:p.color, + name:p.name, fullName:p.fullName, area:p.area, urban:p.urban, rural:p.rural} + }); const data = states.concat(provinces); const root = d3.stratify().parentId(d => d.state)(data).sum(d => d.area); @@ -371,9 +373,9 @@ function editProvinces() { : this.value === "rural" ? d => d.rural : this.value === "urban" ? d => d.urban : d => d.rural + d.urban; - - const newRoot = d3.stratify().parentId(d => d.state)(data).sum(value); - node.data(treeLayout(newRoot).leaves()); + + root.sum(value); + node.data(treeLayout(root).leaves()); node.select("rect").transition().duration(1500) .attr("x", d => d.x0).attr("y", d => d.y0) diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index 75bdfb15..73f0f45d 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -419,7 +419,7 @@ function editStates() { const node = graph.selectAll("g").data(root.leaves()).enter() .append("g").attr("transform", d => `translate(${d.x},${d.y})`) - .attr("data-id", d => d.data.id) + .attr("data-id", d => d.data.i) .on("mouseenter", d => showInfo(event, d)) .on("mouseleave", d => hideInfo(event, d)); diff --git a/modules/utils.js b/modules/utils.js index e67e6fa9..b5f90884 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -543,5 +543,10 @@ function getAbsolutePath(href) { return link.href; } +// wrap URL into html a element +function link(URL, description) { + return `${description}` +} + // localStorageDB !function(){function e(t,o){return n?void(n.transaction("s").objectStore("s").get(t).onsuccess=function(e){var t=e.target.result&&e.target.result.v||null;o(t)}):void setTimeout(function(){e(t,o)},100)}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!t)return void console.error("indexDB not supported");var n,o={k:"",v:""},r=t.open("d2",1);r.onsuccess=function(e){n=this.result},r.onerror=function(e){console.error("indexedDB request error"),console.log(e)},r.onupgradeneeded=function(e){n=null;var t=e.target.result.createObjectStore("s",{keyPath:"k"});t.transaction.oncomplete=function(e){n=e.target.db}},window.ldb={get:e,set:function(e,t){o.k=e,o.v=t,n.transaction("s","readwrite").objectStore("s").put(o)}}}(); \ No newline at end of file From 5eb24252e1627bd4207c90f02db8a0530efc6660 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 18 Sep 2019 21:30:48 +0300 Subject: [PATCH 02/18] 1.0.41 --- index.html | 22 ++++++++- main.js | 39 ++++++++++----- modules/cultures-generator.js | 92 ++++++++++++++++++++++++++++------- modules/names-generator.js | 62 +++++++++++------------ modules/ui/markers-editor.js | 2 + modules/ui/options.js | 8 +++ modules/ui/tools.js | 7 ++- 7 files changed, 171 insertions(+), 61 deletions(-) diff --git a/index.html b/index.html index 1eca7f3a..77569b0a 100644 --- a/index.html +++ b/index.html @@ -1553,13 +1553,31 @@ Cultures number - + - + + + + + + Cultures set + + + + + + diff --git a/main.js b/main.js index f469ea95..e24b7355 100644 --- a/main.js +++ b/main.js @@ -603,7 +603,7 @@ function generate() { drawStates(); drawBorders(); BurgsAndStates.drawStateLabels(); - addZone(); + addZones(); addMarkers(); Names.getMapName(); @@ -1176,19 +1176,36 @@ function rankCells() { } // add a zone as an example: rebels along one border -function addZone() { - const cells = pack.cells, states = pack.states; - const state = states.find(s => s.i && s.neighbors.size > 0 && s.neighbors.values().next().value); - if (!state) return; +function addZones() { + console.time("addZones"); + const data = [], cells = pack.cells, states = pack.states; - const neib = state.neighbors.values().next().value; - const data = cells.i.filter(i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neib)); + void function addRebels() { + const state = states.find(s => s.i && s.neighbors.size > 0 && s.neighbors.values().next().value); + if (!state) return; + + const neib = state.neighbors.values().next().value; + const cellsArray = cells.i.filter(i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neib)); - const rebels = rw({Rebels:5, Insurgents:2, Recusants:1, Mutineers:1, Rioters:1, Dissenters:1, Secessionists:1, Insurrection:2, Rebellion:1, Conspiracy:2}); - const name = getAdjective(states[neib].name) + " " + rebels; + const rebels = rw({"Rebels":5, "Insurgents":2, "Recusants":1, + "Mutineers":1, "Rioters":1, "Dissenters":1, "Secessionists":1, + "Insurrection":2, "Rebellion":1, "Conspiracy":2}); + const name = getAdjective(states[neib].name) + " " + rebels; + data.push({name, cells:cellsArray, fill:"url(#hatch3)"}); + }() - const zone = zones.append("g").attr("id", "zone0").attr("data-description", name).attr("data-cells", data).attr("fill", "url(#hatch3)"); - zone.selectAll("polygon").data(data).enter().append("polygon").attr("points", d => getPackPolygon(d)).attr("id", d => "zone0_"+d); + // void function addDisease() { + + // }() + + void function drawZones() { + zones.selectAll("g").data(data).enter().append("g") + .attr("id", (d, i) => "zone"+i).attr("data-description", d => d.name).attr("data-cells", d => d.cells.join(",")).attr("fill", d => d.fill) + .selectAll("polygon").data(d => d.cells).enter().append("polygon") + .attr("points", d => getPackPolygon(d)).attr("id", function(d) {return this.parentNode.id+"_"+d}); + }() + + console.timeEnd("addZones"); } // add some markers as an example diff --git a/modules/cultures-generator.js b/modules/cultures-generator.js index 58315902..a5632e9c 100644 --- a/modules/cultures-generator.js +++ b/modules/cultures-generator.js @@ -64,11 +64,14 @@ } function getRandomCultures(c) { - const d = getDefault(); + const d = getDefault(), n = d.length-1; + const count = Math.min(c, d.length); const cultures = []; - while (cultures.length < c) { - let culture = d[0]; - do {culture = d[rand(d.length-1)];} while (Math.random() > culture.odd || cultures.find(c => c.name === culture.name)) + while (cultures.length < count) { + let culture = d[rand(n)]; + do { + culture = d[rand(n)]; + } while (Math.random() > culture.odd || cultures.find(c => c.name === culture.name)) cultures.push(culture); } return cultures; @@ -113,6 +116,61 @@ } const getDefault = function() { + if (culturesSet.value === "european") { + return [ + {name:"Shwazen", base:0, odd: 1}, + {name:"Angshire", base:1, odd: 1}, + {name:"Luari", base:2, odd: 1}, + {name:"Tallian", base:3, odd: 1}, + {name:"Astellian", base:4, odd: 1}, + {name:"Slovan", base:5, odd: 1}, + {name:"Norse", base:6, odd: 1}, + {name:"Elladan", base:7, odd: 1}, + {name:"Romian", base:8, odd: .2}, + {name:"Soumi", base:9, odd: 1}, + {name:"Portuzian", base:13, odd: 1}, + {name:"Vengrian", base: 15, odd: 1}, + {name:"Turchian", base: 16, odd: .05}, + {name:"Euskati", base: 20, odd: .05}, + {name:"Keltan", base: 22, odd: .05} + ]; + } + + if (culturesSet.value === "oriental") { + return [ + {name:"Koryo", base:10, odd: 1}, + {name:"Hantzu", base:11, odd: 1}, + {name:"Yamoto", base:12, odd: 1}, + {name:"Turchian", base: 16, odd: 1}, + {name:"Berberan", base: 17, odd: .2}, + {name:"Eurabic", base: 18, odd: 1}, + {name:"Efratic", base: 23, odd: .1}, + {name:"Tehrani", base: 24, odd: 1}, + {name:"Maui", base: 25, odd: .2}, + {name:"Carnatic", base: 26, odd: .5}, + {name:"Vietic", base: 29, odd: .8}, + {name:"Guantzu", base:30, odd: .5}, + {name:"Ulus", base:31, odd: 1} + ]; + } + + if (culturesSet.value === "english") { + const getName = () => Names.getBase(1, 5, 9, "", 0); + return [ + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1}, + {name:getName(), base:1, odd: 1} + ]; + } + + // all-world return [ {name:"Shwazen", base:0, odd: .7}, {name:"Angshire", base:1, odd: 1}, @@ -123,28 +181,28 @@ {name:"Norse", base:6, odd: .7}, {name:"Elladan", base:7, odd: .7}, {name:"Romian", base:8, odd: .7}, - {name:"Soumi", base:9, odd: .4}, - {name:"Koryo", base:10, odd: .5}, - {name:"Hantzu", base:11, odd: .5}, - {name:"Yamoto", base:12, odd: .5}, + {name:"Soumi", base:9, odd: .3}, + {name:"Koryo", base:10, odd: .1}, + {name:"Hantzu", base:11, odd: .1}, + {name:"Yamoto", base:12, odd: .1}, {name:"Portuzian", base:13, odd: .4}, - {name:"Nawatli", base:14, odd: .2}, + {name:"Nawatli", base:14, odd: .1}, {name:"Vengrian", base: 15, odd: .2}, {name:"Turchian", base: 16, odd: .2}, - {name:"Berberan", base: 17, odd: .2}, + {name:"Berberan", base: 17, odd: .1}, {name:"Eurabic", base: 18, odd: .2}, - {name:"Inuk", base: 19, odd: .1}, - {name:"Euskati", base: 20, odd: .1}, + {name:"Inuk", base: 19, odd: .05}, + {name:"Euskati", base: 20, odd: .05}, {name:"Negarian", base: 21, odd: .05}, - {name:"Keltan", base: 22, odd: .1}, - {name:"Efratic", base: 23, odd: .1}, + {name:"Keltan", base: 22, odd: .05}, + {name:"Efratic", base: 23, odd: .05}, {name:"Tehrani", base: 24, odd: .1}, {name:"Maui", base: 25, odd: .05}, - {name:"Carnatic", base: 26, odd: .1}, - {name:"Inqan", base: 27, odd: .1}, + {name:"Carnatic", base: 26, odd: .05}, + {name:"Inqan", base: 27, odd: .05}, {name:"Kiswaili", base: 28, odd: .1}, {name:"Vietic", base: 29, odd: .1}, - {name:"Guantzu", base:30, odd: 1}, + {name:"Guantzu", base:30, odd: .1}, {name:"Ulus", base:31, odd: .1} ]; } diff --git a/modules/names-generator.js b/modules/names-generator.js index 6e6a7603..82e0bd87 100644 --- a/modules/names-generator.js +++ b/modules/names-generator.js @@ -126,8 +126,9 @@ // exclude endings inappropriate for states name if (name.includes(" ")) name = capitalize(name.replace(/ /g, "").toLowerCase()); // don't allow multiword state names if (name.length > 6 && name.slice(-4) === "berg") name = name.slice(0,-4); // remove -berg for any + if (name.length > 5 && name.slice(-3) === "ton") name = name.slice(0,-3); // remove -ton for any + if (base === 5 && ["sk", "ev", "ov"].includes(name.slice(-2))) name = name.slice(0,-2); // remove -sk/-ev/-ov for Ruthenian - else if (base === 1 && name.length > 5 && name.slice(-3) === "ton") name = name.slice(0,-3); // remove -ton for English else if (base === 12) return vowel(name.slice(-1)) ? name : name + "u"; // Japanese ends on any vowel or -u else if (base === 18 && Math.random() < .4) name = vowel(name.slice(0,1).toLowerCase()) ? "Al" + name.toLowerCase() : "Al " + name; // Arabic starts with -Al @@ -139,25 +140,26 @@ } else if (Math.random() < .4) return name; // 60% for cc and vc // define suffix - let suffix = ""; + let suffix = "ia"; // standard suffix + const rnd = Math.random(), l = name.length; - if (base === 3) suffix = rnd < .03 && l < 7 ? "terra" : "ia"; // Italian - else if (base === 4) suffix = rnd < .03 && l < 7 ? "terra" : "ia"; // Spanish - else if (base === 13) suffix = rnd < .03 && l < 7 ? "terra" : "ia"; // Portuguese - else if (base === 2) suffix = rnd < .03 && l < 7 ? "terre" : "ia"; // French - else if (base === 0) suffix = rnd < .5 && l < 7 ? "land" : "ia"; // German - else if (base === 1) suffix = rnd < .4 && l < 7 ? "land" : "ia"; // English - else if (base === 6) suffix = rnd < .3 && l < 7 ? "land" : "ia"; // Nordic - else if (base === 7) suffix = rnd < .1 ? "eia" : "ia"; // Greek - else if (base === 9) suffix = rnd < .35 ? "maa" : "ia"; // Finnic - else if (base === 15) suffix = rnd < .6 && l < 6 ? "orszag" : "ia"; // Hungarian + if (base === 3 && rnd < .03 && l < 7) suffix = "terra"; // Italian + else if (base === 4 && rnd < .03 && l < 7) suffix = "terra"; // Spanish + else if (base === 13 && rnd < .03 && l < 7) suffix = "terra"; // Portuguese + else if (base === 2 && rnd < .03 && l < 7) suffix = "terre"; // French + else if (base === 0 && rnd < .5 && l < 7) suffix = "land"; // German + else if (base === 1 && rnd < .4 && l < 7 ) suffix = "land"; // English + else if (base === 6 && rnd < .3 && l < 7) suffix = "land"; // Nordic + else if (base === 7 && rnd < .1) suffix = "eia"; // Greek + else if (base === 9 && rnd < .35) suffix = "maa"; // Finnic + else if (base === 15 && rnd < .6 && l < 6) suffix = "orszag"; // Hungarian else if (base === 16) suffix = rnd < .5 ? "stan" : "ya"; // Turkish else if (base === 10) suffix = "guk"; // Korean else if (base === 11) suffix = " Guo"; // Chinese - else if (base === 14) suffix = rnd < .6 && l < 7 ? "tlan" : "co"; // Nahuatl - else if (base === 17) suffix = rnd < .8 ? "a" : "ia"; // Berber - else if (base === 18) suffix = rnd < .8 ? "a" : "ia"; // Arabic - else suffix = "ia" // other + else if (base === 14) suffix = rnd < .6 && l < 6 ? "tlan" : "co"; // Nahuatl + else if (base === 17 && rnd < .8) suffix = "a"; // Berber + else if (base === 18 && rnd < .8) suffix = "a"; // Arabic + return validateSuffix(name, suffix); } @@ -194,30 +196,30 @@ // name, min length, max length, letters to allow duplication, multi-word name rate return [ {name: "German", min: 5, max: 12, d: "lt", m: 0}, - {name: "English", min: 6, max: 11, d: "", m: 0.1}, - {name: "French", min: 5, max: 13, d: "nlrs", m: 0.1}, - {name: "Italian", min: 5, max: 12, d: "cltr", m: 0.1}, + {name: "English", min: 6, max: 11, d: "", m: .1}, + {name: "French", min: 5, max: 13, d: "nlrs", m: .1}, + {name: "Italian", min: 5, max: 12, d: "cltr", m: .1}, {name: "Castillian", min: 5, max: 11, d: "lr", m: 0}, {name: "Ruthenian", min: 5, max: 10, d: "", m: 0}, - {name: "Nordic", min: 6, max: 10, d: "kln", m: 0.1}, - {name: "Greek", min: 5, max: 11, d: "s", m: 0.1}, - {name: "Roman", min: 6, max: 11, d: "ln", m: 0.1}, + {name: "Nordic", min: 6, max: 10, d: "kln", m: .1}, + {name: "Greek", min: 5, max: 11, d: "s", m: .1}, + {name: "Roman", min: 6, max: 11, d: "ln", m: .1}, {name: "Finnic", min: 5, max: 11, d: "akiut", m: 0}, {name: "Korean", min: 5, max: 11, d: "", m: 0}, {name: "Chinese", min: 5, max: 10, d: "", m: 0}, {name: "Japanese", min: 4, max: 10, d: "", m: 0}, - {name: "Portuguese", min: 5, max: 11, d: "", m: 0.1}, + {name: "Portuguese", min: 5, max: 11, d: "", m: .1}, {name: "Nahuatl", min: 6, max: 13, d: "l", m: 0}, - {name: "Hungarian", min: 6, max: 13, d: "", m: 0.1}, + {name: "Hungarian", min: 6, max: 13, d: "", m: .1}, {name: "Turkish", min: 4, max: 10, d: "", m: 0}, - {name: "Berber", min: 4, max: 10, d: "s", m: 0.2}, - {name: "Arabic", min: 4, max: 9, d: "ae", m: 0.2}, + {name: "Berber", min: 4, max: 10, d: "s", m: .2}, + {name: "Arabic", min: 4, max: 9, d: "ae", m: .2}, {name: "Inuit", min: 5, max: 15, d: "alutsn", m: 0}, - {name: "Basque", min: 4, max: 11, d: "r", m: 0.1}, - {name: "Nigerian", min: 4, max: 10, d: "", m: 0.3}, + {name: "Basque", min: 4, max: 11, d: "r", m: .1}, + {name: "Nigerian", min: 4, max: 10, d: "", m: .3}, {name: "Celtic", min: 4, max: 12, d: "nld", m: 0}, - {name: "Mesopotamian", min: 4, max: 9, d: "srpl", m: 0.1}, - {name: "Iranian", min: 5, max: 11, d: "", m: 0.1}, + {name: "Mesopotamian", min: 4, max: 9, d: "srpl", m: .1}, + {name: "Iranian", min: 5, max: 11, d: "", m: .1}, {name: "Hawaiian", min: 5, max: 10, d: "auo", m: 1}, {name: "Karnataka", min: 5, max: 11, d: "tnl", m: 0}, {name: "Quechua", min: 6, max: 12, d: "l", m: 0}, diff --git a/modules/ui/markers-editor.js b/modules/ui/markers-editor.js index b1a28dd1..9df4b88a 100644 --- a/modules/ui/markers-editor.js +++ b/modules/ui/markers-editor.js @@ -487,6 +487,8 @@ function editMarker() { buttons: { Remove: function() { $(this).dialog("close"); + const index = notes.findIndex(n => n.id === elSelected.attr("id")); + if (index != -1) notes.splice(index, 1); elSelected.remove(); $("#markerEditor").dialog("close"); }, diff --git a/modules/ui/options.js b/modules/ui/options.js index 569a58a5..67f2d8a8 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -670,6 +670,7 @@ optionsContent.addEventListener("input", function(event) { else if (id === "densityInput" || id === "densityOutput") changeCellsDensity(+value); else if (id === "culturesInput") culturesOutput.value = value; else if (id === "culturesOutput") culturesInput.value = value; + else if (id === "culturesSet") changeCultureSet(); else if (id === "regionsInput" || id === "regionsOutput") changeStatesNumber(value); else if (id === "provincesInput") provincesOutput.value = value; else if (id === "provincesOutput") provincesOutput.value = value; @@ -795,6 +796,12 @@ function changeCellsDensity(value) { else densityOutput.style.color = "#038603"; } +function changeCultureSet() { + const max = culturesSet.selectedOptions[0].dataset.max; + culturesInput.max = culturesOutput.max = max + if (+culturesOutput.value > +max) culturesInput.value = culturesOutput.value = max; +} + function changeStatesNumber(value) { regionsInput.value = regionsOutput.value = value; burgLabels.select("#capitals").attr("data-size", Math.max(rn(6 - value / 20), 3)); @@ -880,6 +887,7 @@ function randomizeOptions() { if (!locked("power")) powerInput.value = powerOutput.value = gauss(3, 2, 0, 10); if (!locked("neutral")) neutralInput.value = neutralOutput.value = rn(1 + Math.random(), 1); if (!locked("cultures")) culturesInput.value = culturesOutput.value = gauss(12, 3, 5, 30); + changeCultureSet(); // 'Configure World' settings if (!locked("prec")) precInput.value = precOutput.value = gauss(100, 20, 5, 500); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 23a0ab10..4b8ffedd 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -202,7 +202,12 @@ function regenerateReligions() { } function regenerateMarkers() { - markers.selectAll("use").remove(); + // remove existing markers and assigned notes + markers.selectAll("use").each(function() { + const index = notes.findIndex(n => n.id === this.id); + if (index != -1) notes.splice(index, 1); + }).remove(); + addMarkers(gauss(1, .5, .3, 5, 2)); } From 795d5330100e13171b50f4e18fb2271131858abc Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 19 Sep 2019 12:07:49 +0300 Subject: [PATCH 03/18] 1.0.42 --- modules/save-and-load.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 0e983662..ea3b7bb2 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -776,7 +776,7 @@ function parseLoadedData(data) { // 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(); + addZones(); if (!markers.selectAll("*").size()) {addMarkers(); turnButtonOn("toggleMarkers");} // 1.0 add fogging layer (state focus) From ce89fb0035c343bfdd30e0d93b0c428e6f411acd Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 19 Sep 2019 12:07:57 +0300 Subject: [PATCH 04/18] 1.0.42 --- modules/ui/heightmap-editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 8cee6258..0b792be3 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -174,7 +174,7 @@ function getHeight(h) { drawStates(); drawBorders(); BurgsAndStates.drawStateLabels(); - addZone(); + addZones(); addMarkers(); console.timeEnd("regenerateErasedData"); console.groupEnd("Edit Heightmap"); @@ -1190,4 +1190,4 @@ function getHeight(h) { } } -} \ No newline at end of file +} From be4caf0c246e00fd9023e60485e62c6b4d382c2b Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 19 Sep 2019 22:20:16 +0300 Subject: [PATCH 05/18] 1.0.43 --- main.js | 76 +++++++++++++++++++++++++++++++--- modules/religions-generator.js | 2 +- modules/save-and-load.js | 2 +- modules/ui/heightmap-editor.js | 2 +- modules/ui/tools.js | 1 + 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/main.js b/main.js index e24b7355..4271b63c 100644 --- a/main.js +++ b/main.js @@ -1175,11 +1175,13 @@ function rankCells() { console.timeEnd('rankCells'); } -// add a zone as an example: rebels along one border +// add a some zones function addZones() { console.time("addZones"); - const data = [], cells = pack.cells, states = pack.states; + const data = [], cells = pack.cells, states = pack.states, burgs = pack.burgs; + //const used = new Uint8Array(cells.i.length); // to store used cells + // rebels along a state border void function addRebels() { const state = states.find(s => s.i && s.neighbors.size > 0 && s.neighbors.values().next().value); if (!state) return; @@ -1191,16 +1193,78 @@ function addZones() { "Mutineers":1, "Rioters":1, "Dissenters":1, "Secessionists":1, "Insurrection":2, "Rebellion":1, "Conspiracy":2}); const name = getAdjective(states[neib].name) + " " + rebels; - data.push({name, cells:cellsArray, fill:"url(#hatch3)"}); + data.push({name, type:"Rebels", cells:cellsArray, fill:"url(#hatch3)"}); }() - // void function addDisease() { + // disease starting in a random city + void function addDisease() { + const burg = ra(burgs.filter(b => b.i && !b.removed)); // random burg + if (!burg) return; - // }() + const cellsArray = [], cost = [], power = rand(20, 40); + const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); + queue.queue({e:burg.cell, p:0}); + + while (queue.length) { + const next = queue.dequeue(); + if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); + + cells.c[next.e].forEach(function(e) { + const r = cells.road[next.e]; + const c = r ? Math.max(10 - r, 1) : 100; + const p = next.p + c; + if (p > power) return; + + if (!cost[e] || p < cost[e]) { + cost[e] = p; + queue.queue({e, p}); + } + }); + } + + const adjective = () => ra(["Great", "Silent", "Severe", "Blind", "Unknown", "Loud", "Deadly", "Burning", "Bloody", "Brutal", "Fatal"]); + const animal = () => ra(["Ape", "Bear", "Boar", "Cat", "Cow", "Dog", "Pig", "Fox", "Bird", "Horse", "Rat", "Raven", "Sheep", "Spider", "Wolf"]); + const color = () => ra(["Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"]); + + const type = rw({"Fever":5, "Pestilence":2, "Flu":2, "Pox":2, "Smallpox":2, "Plague":4, "Cholera":2, "Ague":1, "Dropsy":1, "Leprosy":2}); + const name = rw({[color()]:4, [animal()]:2, [adjective()]:1}) + " " + type; + data.push({name, type:"Disease", cells:cellsArray, fill:"url(#hatch12)"}); + }() + + // disaster starting in a random city + void function addDisaster() { + const burg = ra(burgs.filter(b => b.i && !b.removed)); // random burg + if (!burg) return; + + const cellsArray = [], cost = [], power = rand(10, 30); + const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p}); + queue.queue({e:burg.cell, p:0}); + + while (queue.length) { + const next = queue.dequeue(); + if (cells.burg[next.e] || cells.pop[next.e]) cellsArray.push(next.e); + + cells.c[next.e].forEach(function(e) { + const c = rand(1, 10); + const p = next.p + c; + if (p > power) return; + + if (!cost[e] || p < cost[e]) { + cost[e] = p; + queue.queue({e, p}); + } + }); + } + + // Volcanic Eruption, Fault Line, Avalanche, Tsunami + const type = rw({"Famine":5, "Drought":3, "Dearth":1, "Earthquake":3, "Tornadoes":1, "Wildfires":1, "Flood":3}); + data.push({name:type, type:"Disaster", cells:cellsArray, fill:"url(#hatch5)"}); + }() void function drawZones() { zones.selectAll("g").data(data).enter().append("g") - .attr("id", (d, i) => "zone"+i).attr("data-description", d => d.name).attr("data-cells", d => d.cells.join(",")).attr("fill", d => d.fill) + .attr("id", (d, i) => "zone"+i).attr("data-description", d => d.name).attr("data-type", d => d.type) + .attr("data-cells", d => d.cells.join(",")).attr("fill", d => d.fill) .selectAll("polygon").data(d => d.cells).enter().append("polygon") .attr("points", d => getPackPolygon(d)).attr("id", function(d) {return this.parentNode.id+"_"+d}); }() diff --git a/modules/religions-generator.js b/modules/religions-generator.js index 9abaf8a6..dc705c68 100644 --- a/modules/religions-generator.js +++ b/modules/religions-generator.js @@ -22,7 +22,7 @@ number: ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve"], being: ["God", "Goddess", "Lord", "Lady", "Deity", "Creator", "Maker", "Overlord", "Ruler", "Chief", "Master", "Spirit", "Ancestor", "Father", "Forebear", "Forefather", "Mother", "Brother", "Sister", "Elder", "Numen", "Ancient", "Virgin", "Giver", "Council", "Guardian", "Reaper"], animal: ["Antelope", "Ape", "Badger", "Bear", "Beaver", "Bison", "Boar", "Buffalo", "Cat", "Cobra", "Crane", "Crocodile", "Crow", "Deer", "Dog", "Eagle", "Elk", "Fox", "Goat", "Goose", "Hare", "Hawk", "Heron", "Horse", "Hyena", "Ibis", "Jackal", "Jaguar", "Lark", "Leopard", "Lion", "Mantis", "Marten", "Moose", "Mule", "Narwhal", "Owl", "Panther", "Rat", "Raven", "Rook", "Scorpion", "Shark", "Sheep", "Snake", "Spider", "Swan", "Tiger", "Turtle", "Viper", "Vulture", "Walrus", "Wolf", "Wolverine", "Worm", "Camel", "Falcon", "Hound", "Ox", "Serpent"], - adjective: ["New", "Good", "High", "Old", "Great", "Big", "Young", "Major", "Strong", "Happy", "Last", "Main", "Huge", "Far", "Beautiful", "Wild", "Fair", "Prime", "Crazy", "Ancient", "Golden", "Proud", "Secret", "Lucky", "Sad", "Silent", "Latter", "Severe", "Fat", "Holy", "Pure", "Aggressive", "Honest", "Giant", "Mad", "Pregnant", "Distant", "Lost", "Broken", "Blind", "Friendly", "Unknown", "Sleeping", "Slumbering", "Loud", "Hungry", "Wise", "Worried", "Sacred", "Magical", "Superior", "Patient", "Dead", "Deadly", "Peaceful", "Grateful", "Frozen", "Evil", "Scary", "Burning", "Divine", "Bloody", "Dying", "Waking", "Brutal", "Unhappy", "Calm", "Cruel", "Favorable", "Blond", "Explicit", "Disturbing", "Devastating", "Brave", "Sunny", "Troubled", "Flying", "Sustainable", "Marine", "Fatal", "Inherent", "Selected", "Naval", "Cheerful", "Almighty", "Benevolent", "Eternal", "Immutable", "Infallible"], + adjective: ["New", "Good", "High", "Old", "Great", "Big", "Young", "Major", "Strong", "Happy", "Last", "Main", "Huge", "Far", "Beautiful", "Wild", "Fair", "Prime", "Crazy", "Ancient", "Proud", "Secret", "Lucky", "Sad", "Silent", "Latter", "Severe", "Fat", "Holy", "Pure", "Aggressive", "Honest", "Giant", "Mad", "Pregnant", "Distant", "Lost", "Broken", "Blind", "Friendly", "Unknown", "Sleeping", "Slumbering", "Loud", "Hungry", "Wise", "Worried", "Sacred", "Magical", "Superior", "Patient", "Dead", "Deadly", "Peaceful", "Grateful", "Frozen", "Evil", "Scary", "Burning", "Divine", "Bloody", "Dying", "Waking", "Brutal", "Unhappy", "Calm", "Cruel", "Favorable", "Blond", "Explicit", "Disturbing", "Devastating", "Brave", "Sunny", "Troubled", "Flying", "Sustainable", "Marine", "Fatal", "Inherent", "Selected", "Naval", "Cheerful", "Almighty", "Benevolent", "Eternal", "Immutable", "Infallible"], genitive: ["Day", "Life", "Death", "Night", "Home", "Fog", "Snow", "Winter", "Summer", "Cold", "Springs", "Gates", "Nature", "Thunder", "Lightning", "War", "Ice", "Frost", "Fire", "Doom", "Fate", "Pain", "Heaven", "Justice", "Light", "Love", "Time", "Victory"], theGenitive: ["World", "Word", "South", "West", "North", "East", "Sun", "Moon", "Peak", "Fall", "Dawn", "Eclipse", "Abyss", "Blood", "Tree", "Earth", "Harvest", "Rainbow", "Sea", "Sky", "Stars", "Storm", "Underworld", "Wild"], color: ["Dark", "Light", "Bright", "Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"] diff --git a/modules/save-and-load.js b/modules/save-and-load.js index 0e983662..ea3b7bb2 100644 --- a/modules/save-and-load.js +++ b/modules/save-and-load.js @@ -776,7 +776,7 @@ function parseLoadedData(data) { // 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(); + addZones(); if (!markers.selectAll("*").size()) {addMarkers(); turnButtonOn("toggleMarkers");} // 1.0 add fogging layer (state focus) diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index 8cee6258..7f5b34ef 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -174,7 +174,7 @@ function getHeight(h) { drawStates(); drawBorders(); BurgsAndStates.drawStateLabels(); - addZone(); + addZones(); addMarkers(); console.timeEnd("regenerateErasedData"); console.groupEnd("Edit Heightmap"); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 4b8ffedd..a4256988 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -249,6 +249,7 @@ function addLabelOnClick() { const x = width / -2; // x offset; example.remove(); + group.classed("hidden", false); group.append("text").attr("id", id) .append("textPath").attr("xlink:href", "#textPath_"+id).attr("startOffset", "50%").attr("font-size", "100%") .append("tspan").attr("x", x).text(name); From 6517e231e8f3c2267ec68b4fd91750485228de39 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 21 Sep 2019 00:13:29 +0300 Subject: [PATCH 06/18] v1.0.44 --- index.css | 22 +++---- index.html | 92 ++++++++++++++++++----------- modules/ui/biomes-editor.js | 1 + modules/ui/burg-editor.js | 33 +++++++++++ modules/ui/burgs-editor.js | 2 +- modules/ui/cultures-editor.js | 1 + modules/ui/diplomacy-editor.js | 1 + modules/ui/heightmap-editor.js | 2 +- modules/ui/labels-editor.js | 9 ++- modules/ui/layers.js | 102 ++++++++++++++++++++++++--------- modules/ui/options.js | 18 ++++++ modules/ui/provinces-editor.js | 5 +- modules/ui/relief-editor.js | 1 + modules/ui/religions-editor.js | 1 + modules/ui/rivers-editor.js | 1 + modules/ui/routes-editor.js | 9 ++- modules/ui/states-editor.js | 1 + modules/ui/tools.js | 54 +++++++++-------- modules/ui/zones-editor.js | 1 + modules/utils.js | 8 +-- 20 files changed, 260 insertions(+), 104 deletions(-) diff --git a/index.css b/index.css index 2f077fa0..b442fd05 100644 --- a/index.css +++ b/index.css @@ -252,7 +252,7 @@ i.icon-lock { #brushCircle { stroke: #373737; stroke-width: 1.5px; - stroke-dasharray: 6; + stroke-dasharray: 7; stroke-linecap: butt; fill: none; } @@ -474,13 +474,7 @@ input[type="color"]::-webkit-color-swatch-wrapper { font-weight: bold; } -#styleContent button.styleButton { - font-size: 70%; - border-radius: 15%; - margin: 0; -} - -#styleContent button.presetButton { +#layersContent button.presetButton { position: absolute; height: 2em; border-radius: 15%; @@ -488,6 +482,13 @@ input[type="color"]::-webkit-color-swatch-wrapper { font-size: .7em; } +#styleContent button.styleButton { + font-size: 70%; + border-radius: 15%; + margin: 0; +} + +#layersContent button.active, #styleContent button:active { transform: translate(0px, 1px); } @@ -531,9 +532,10 @@ input[type="color"]::-webkit-color-swatch-wrapper { } .tab > button.options { - width: 23.25%; + /* width: 23.25%; */ + width: 18.6%; height: 100%; - padding: 7px 10px; + padding: 7px 0px; } button.options { diff --git a/index.html b/index.html index 77569b0a..a3faa870 100644 --- a/index.html +++ b/index.html @@ -890,13 +890,14 @@
- + +
-
+

Layers preset:

@@ -980,7 +983,7 @@ - Group + Group @@ -1460,7 +1463,7 @@
-

Toggle filters:

+

Toggle global filters:

@@ -2019,6 +2022,8 @@
+ + + @@ -2069,6 +2075,8 @@
+ + @@ -2201,6 +2209,7 @@
+ @@ -2226,6 +2235,14 @@
+ + + @@ -2322,8 +2339,8 @@