From af62ff915c1d85ad66e75554c7c2241dfc8d7c87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Anna=20Veronika?=
<39062493+annapanni@users.noreply.github.com>
Date: Sat, 2 Apr 2022 22:42:54 +0200
Subject: [PATCH] Dev csv (#761)
* import cultures feature
* remove debug messages
* code cleanup
---
index.html | 9 ++-
modules/io/formats.js | 19 ++++++
modules/ui/cultures-editor.js | 114 +++++++++++++++++++++++++---------
3 files changed, 110 insertions(+), 32 deletions(-)
create mode 100644 modules/io/formats.js
diff --git a/index.html b/index.html
index a5733917..20930605 100644
--- a/index.html
+++ b/index.html
@@ -1426,7 +1426,7 @@
Join our Discord server and Reddit community to ask questions, get help and share maps.
-
+
The project is under active development. Creator and main maintainer: Azgaar. To track the development progress see the devboard .
For older versions see the changelog . Please report bugs here . You can also contact me directly via email .
@@ -2610,7 +2610,7 @@
Sultanate
Tsardom
Ulus
- Viceroyalty
+ Viceroyalty
Chancellery
@@ -2852,6 +2852,7 @@
+
@@ -3692,6 +3693,7 @@
+
@@ -4341,7 +4343,7 @@
-
+
@@ -4583,6 +4585,7 @@
+
diff --git a/modules/io/formats.js b/modules/io/formats.js
new file mode 100644
index 00000000..329d85db
--- /dev/null
+++ b/modules/io/formats.js
@@ -0,0 +1,19 @@
+"use strict"
+
+window.Formats = (function () {
+ async function csvParser (file, separator=",") {
+ const txt = await file.text();
+ const rows = txt.split("\n");
+ const headers = rows.shift().split(separator).map(x => x.toLowerCase());
+ const data = rows.filter(a => a.trim()!=="").map(r=>r.split(separator));
+ return {
+ headers,
+ data,
+ iterator: function* (sortf){
+ const dataset = sortf? this.data.sort(sortf):this.data;
+ for (const d of dataset)
+ yield Object.fromEntries(d.map((a, i) => [this.headers[i], a]));
+ }};
+ }
+ return {csvParser};
+})();
diff --git a/modules/ui/cultures-editor.js b/modules/ui/cultures-editor.js
index 50b5bc63..65d5fd38 100644
--- a/modules/ui/cultures-editor.js
+++ b/modules/ui/cultures-editor.js
@@ -1,5 +1,6 @@
"use strict";
function editCultures() {
+ const cultureTypes = ["Generic", "River", "Lake", "Naval", "Nomadic", "Hunting", "Highland"];
if (customization) return;
closeDialogs("#culturesEditor, .stable");
if (!layerIsOn("toggleCultures")) toggleCultures();
@@ -37,6 +38,9 @@ function editCultures() {
document.getElementById("culturesEditNamesBase").addEventListener("click", editNamesbase);
document.getElementById("culturesAdd").addEventListener("click", enterAddCulturesMode);
document.getElementById("culturesExport").addEventListener("click", downloadCulturesData);
+ document.getElementById("culturesImport").addEventListener("click", () => document.getElementById("culturesCSVToLoad").click());
+
+ document.getElementById("culturesCSVToLoad").addEventListener("change", uploadCulturesData);
function refreshCulturesEditor() {
culturesCollectStatistics();
@@ -169,8 +173,7 @@ function editCultures() {
function getTypeOptions(type) {
let options = "";
- const types = ["Generic", "River", "Lake", "Naval", "Nomadic", "Hunting", "Highland"];
- types.forEach(t => (options += `${t} `));
+ cultureTypes.forEach(t => (options += `${t} `));
return options;
}
@@ -366,7 +369,7 @@ function editCultures() {
width: "24em",
buttons: {
Apply: function () {
- applyPopulationChange();
+ applyPopulationChange(rural, urban, ruralPop.value, urbanPop.value, culture);
$(this).dialog("close");
},
Cancel: function () {
@@ -375,32 +378,33 @@ function editCultures() {
},
position: {my: "center", at: "center", of: "svg"}
});
+ }
- function applyPopulationChange() {
- const ruralChange = ruralPop.value / rural;
- if (isFinite(ruralChange) && ruralChange !== 1) {
- const cells = pack.cells.i.filter(i => pack.cells.culture[i] === culture);
- cells.forEach(i => (pack.cells.pop[i] *= ruralChange));
- }
- if (!isFinite(ruralChange) && +ruralPop.value > 0) {
- const points = ruralPop.value / populationRate;
- const cells = pack.cells.i.filter(i => pack.cells.culture[i] === culture);
- const pop = rn(points / cells.length);
- cells.forEach(i => (pack.cells.pop[i] = pop));
- }
-
- const urbanChange = urbanPop.value / urban;
- if (isFinite(urbanChange) && urbanChange !== 1) {
- burgs.forEach(b => (b.population = rn(b.population * urbanChange, 4)));
- }
- if (!isFinite(urbanChange) && +urbanPop.value > 0) {
- const points = urbanPop.value / populationRate / urbanization;
- const population = rn(points / burgs.length, 4);
- burgs.forEach(b => (b.population = population));
- }
-
- refreshCulturesEditor();
+ function applyPopulationChange(oldRural, oldUrban, newRural, newUrban, culture) {
+ const ruralChange = newRural / oldRural;
+ if (isFinite(ruralChange) && ruralChange !== 1) {
+ const cells = pack.cells.i.filter(i => pack.cells.culture[i] === culture);
+ cells.forEach(i => (pack.cells.pop[i] *= ruralChange));
}
+ if (!isFinite(ruralChange) && +newRural > 0) {
+ const points = newRural / populationRate;
+ const cells = pack.cells.i.filter(i => pack.cells.culture[i] === culture);
+ const pop = rn(points / cells.length);
+ cells.forEach(i => (pack.cells.pop[i] = pop));
+ }
+
+ const burgs = pack.burgs.filter(b => !b.removed && b.culture === culture);
+ const urbanChange = newUrban / oldUrban;
+ if (isFinite(urbanChange) && urbanChange !== 1) {
+ burgs.forEach(b => (b.population = rn(b.population * urbanChange, 4)));
+ }
+ if (!isFinite(urbanChange) && +newUrban > 0) {
+ const points = newUrban / populationRate / urbanization;
+ const population = rn(points / burgs.length, 4);
+ burgs.forEach(b => (b.population = population));
+ }
+
+ refreshCulturesEditor();
}
function cultureRegenerateBurgs() {
@@ -856,7 +860,7 @@ function editCultures() {
function downloadCulturesData() {
const unit = areaUnit.value === "square" ? distanceUnitInput.value + "2" : areaUnit.value;
- let data = "Id,Culture,Color,Cells,Expansionism,Type,Area " + unit + ",Population,Namesbase,Emblems Shape\n"; // headers
+ let data = "Id,Culture,Color,Cells,Expansionism,Type,Area " + unit + ",Population,Namesbase,Emblems Shape,Origin\n"; // headers
body.querySelectorAll(":scope > div").forEach(function (el) {
data += el.dataset.id + ",";
@@ -869,7 +873,8 @@ function editCultures() {
data += el.dataset.population + ",";
const base = +el.dataset.base;
data += nameBases[base].name + ",";
- data += el.dataset.emblems + "\n";
+ data += el.dataset.emblems + ",";
+ data += pack.cultures[+el.dataset.id].origin + "\n";
});
const name = getFileName("Cultures") + ".csv";
@@ -881,4 +886,55 @@ function editCultures() {
exitCulturesManualAssignment("close");
exitAddCultureMode();
}
+ async function uploadCulturesData() {
+ const csv = await Formats.csvParser(this.files[0]);
+ this.value = "";
+ const cultures = pack.cultures;
+ const shapes = Object.keys(COA.shields.types)
+ .map(type => Object.keys(COA.shields[type]))
+ .flat();
+ const populated = pack.cells.pop.map((c, i) => c? i: null).filter(c => c);
+ cultures.forEach((item) => {if (item.i) item.removed = true});
+ for (const c of csv.iterator((a, b) => +a[0] > +b[0])) {
+ let current;
+ if (+c.id < cultures.length) {
+ current = cultures[c.id];
+ const ratio = current.urban / (current.rural + current.urban);
+ applyPopulationChange(current.rural, current.urban, c.population*(1 - ratio), c.population*ratio, +c.id);
+ } else {
+ current = {
+ i: cultures.length,
+ center: ra(populated),
+ area: 0,
+ cells: 0,
+ origin: 0,
+ rural: 0,
+ urban: 0,
+ }
+ cultures.push(current)
+ }
+ current.name = c.culture;
+ current.code = abbreviate(current.name, cultures.map(c => c.code));
+ current.color = c.color;
+ current.expansionism = +c.expansionism;
+ current.origin = +c.origin;
+ if (cultureTypes.includes(c.type))
+ current.type = c.type;
+ else
+ current.type = "Generic";
+ current.removed = false;
+ const shieldShape = c["emblems shape"].toLowerCase();
+ if (shapes.includes(shieldShape))
+ current.shield = shieldShape
+ else
+ current.shield = "heater";
+
+ const nbi = nameBases.findIndex(n => n.name==c.namesbase);
+ current.base = nbi==-1? 0: nbi;
+ }
+ const validId = cultures.filter(c => !c.removed).map(c => c.i);
+ cultures.forEach(item => item.origin = validId.includes(item.origin)? item.origin:0);
+ cultures[0].origin = null;
+ refreshCulturesEditor();
+ }
}