From d243b1d90680db4945c8da82ba21c872568ca6b5 Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@gmail.com>
Date: Tue, 10 Mar 2020 20:47:37 +0100
Subject: [PATCH] add different arc layouts for each location

---
 src/003-assets/CSS/arcologyBuilding.css |  72 +++++++------
 src/004-base/arcologyBuilding.js        |   4 +-
 src/arcologyBuilding/base.js            | 138 +++++++++++++++++++-----
 src/events/intro/initNationalities.tw   |   5 +
 src/events/intro/terrainIntro.tw        |   5 +
 src/init/storyInit.tw                   |   4 -
 6 files changed, 167 insertions(+), 61 deletions(-)

diff --git a/src/003-assets/CSS/arcologyBuilding.css b/src/003-assets/CSS/arcologyBuilding.css
index 92f86f5c583..a858bf26bb9 100644
--- a/src/003-assets/CSS/arcologyBuilding.css
+++ b/src/003-assets/CSS/arcologyBuilding.css
@@ -1,24 +1,34 @@
 div.building {
     display: flex;
     flex-direction: column;
-    width: 70%;
-    margin: 0 auto;
+    width: 100%;
+}
+
+div.building.basement {
+    box-shadow: 0 -1px 0 #333333;
+    background-image: repeating-linear-gradient(-45deg, transparent, transparent 20px, #333333 20px, #333333 30px);
 }
 
 div.building div.row {
     display: flex;
     flex-direction: row;
-    width: 100%;
-    justify-content: center
+    width: 70%;
+    margin: 0 auto;
+    justify-content: center;
 }
 
-div.building div.cell {
-    outline: 5px solid;
-    outline-offset: -8px;
-    padding: 10px;
+div.building div.outerCell {
     text-align: center;
 }
 
+div.building div.innerCell {
+    margin: 3px;
+    border: 5px solid;
+    padding: 2px;
+    /* overwriting with the default background color to hide the basement indicator */
+    background-color: #111;
+}
+
 /* penthouse formatting */
 div.building div.gridWrapper {
     display: grid;
@@ -49,93 +59,93 @@ div.building div.collapsed {
 
 /* border color for each cell */
 div.building div.row div.apartments {
-    outline-color: limegreen;
+    border-color: limegreen;
 }
 
 div.building div.row div.arcade {
-    outline-color: deeppink;
+    border-color: deeppink;
 }
 
 div.building div.row div.brothel {
-    outline-color: violet;
+    border-color: violet;
 }
 
 div.building div.row div.barracks {
-    outline-color: olivedrab;
+    border-color: olivedrab;
 }
 
 div.building div.row div.club {
-    outline-color: orchid;
+    border-color: orchid;
 }
 
 div.building div.row div.corporateMarket {
-    outline-color: purple;
+    border-color: purple;
 }
 
 div.building div.row div.dairy {
-    outline-color: white;
+    border-color: white;
 }
 
 div.building div.row div.denseApartments {
-    outline-color: seagreen;
+    border-color: seagreen;
 }
 
 div.building div.row div.empty {
-    outline-color: lightgray;
+    border-color: lightgray;
 }
 
 div.building div.row div.farmyard {
-    outline-color: brown;
+    border-color: brown;
 }
 
 div.building div.row div.fsShops {
-    outline-color: mediumpurple;
+    border-color: mediumpurple;
 }
 
 div.building div.row div.manufacturing {
-    outline-color: slategray;
+    border-color: slategray;
 }
 
 div.building div.row div.markets {
-    outline-color: mediumorchid;
+    border-color: mediumorchid;
 }
 
 div.building div.row div.nursery {
-    outline-color: deepskyblue;
+    border-color: deepskyblue;
 }
 
 div.building div.row div.luxuryApartments {
-    outline-color: palegreen;
+    border-color: palegreen;
 }
 
 div.building div.row div.pens {
-    outline-color: goldenrod;
+    border-color: goldenrod;
 }
 
 div.building div.row div.penthouse {
-    outline-color: teal;
+    border-color: teal;
 }
 
 div.building div.row div.pit {
-    outline-color: orangered;
+    border-color: orangered;
 }
 
 div.building div.row div.private {
-    outline-color: red;
+    border-color: red;
 }
 
 div.building div.row div.shops {
-    outline-color: thistle;
+    border-color: thistle;
 }
 
 div.building div.row div.sweatshops {
-    outline-color: gray;
+    border-color: gray;
 }
 
 div.building div.row div.transportHub {
-    outline-color: magenta;
+    border-color: magenta;
 }
 
 div.building div.row div.weaponsManufacturing {
-    outline-color: springgreen;
+    border-color: springgreen;
 }
diff --git a/src/004-base/arcologyBuilding.js b/src/004-base/arcologyBuilding.js
index 19b278a22ed..1bc74651476 100644
--- a/src/004-base/arcologyBuilding.js
+++ b/src/004-base/arcologyBuilding.js
@@ -87,7 +87,9 @@ App.Arcology.Cell.BaseCell = class extends App.Entity.Serializable {
 					const cellClass = eval(`App.Arcology.Cell.${ac}`);
 					if (!(this instanceof cellClass)) {
 						p.append(this._makeUpgrade(`Convert sector to ${cellClass.cellName}.`, () => {
-							containingBuilding.replaceCell(this, new cellClass(1));
+							const newCell = new cellClass(1);
+							newCell.allowedConversions = this.allowedConversions;
+							containingBuilding.replaceCell(this, newCell);
 							repX(-5000, "capEx");
 						}, 50000, "and 5000 reputation as many citizens will lose most of what they own."));
 					}
diff --git a/src/arcologyBuilding/base.js b/src/arcologyBuilding/base.js
index 5ff00d496b1..160edfda4be 100644
--- a/src/arcologyBuilding/base.js
+++ b/src/arcologyBuilding/base.js
@@ -35,22 +35,93 @@ App.Arcology.updateOwnership = function() {
 };
 
 /**
+ * @param {string} location
  * @returns {App.Arcology.Building}
  */
-App.Arcology.defaultBuilding = function() {
+App.Arcology.defaultBuilding = function(location = "default") {
 	const sections = [];
 
 	sections.push(new App.Arcology.Section("penthouse", [[new App.Arcology.Cell.Penthouse()]]));
-	sections.push(new App.Arcology.Section("shops", [[new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1)]]));
-	sections.push(new App.Arcology.Section("apartments",
-		[
-			[new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)],
-			[new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)],
-			[new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)],
-		]
-	));
-	sections.push(new App.Arcology.Section("markets", [[new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1)]]));
-	sections.push(new App.Arcology.Section("manufacturing", [[new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1)]]));
+	sections.push(shops());
+	sections.push(apartments());
+	sections.push(markets());
+	sections.push(manufacturing());
+
+
+	function shops() {
+		const rows = [];
+		if (location === "marine") {
+			rows.push([new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1)]);
+		} else {
+			rows.push([new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1), new App.Arcology.Cell.Shop(1)]);
+		}
+		return new App.Arcology.Section("shops", rows);
+	}
+
+	function apartments() {
+		const rows = [];
+		if (location === "rural") {
+			rows.push([new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)]);
+			rows.push([new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)]);
+		} else {
+			if (location === "marine") {
+				rows.push([new App.Arcology.Cell.Apartment(1, 1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1, 1)]);
+			} else if (location === "oceanic") {
+				rows.push([new App.Arcology.Cell.Apartment(1, 1), new App.Arcology.Cell.Apartment(1, 1), new App.Arcology.Cell.Apartment(1, 1), new App.Arcology.Cell.Apartment(1, 1)]);
+			} else {
+				rows.push([new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)]);
+			}
+			rows.push([new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)]);
+
+			if (location === "urban") {
+				rows.push([new App.Arcology.Cell.Apartment(1, 3), new App.Arcology.Cell.Apartment(1, 3), new App.Arcology.Cell.Apartment(1, 3), new App.Arcology.Cell.Apartment(1, 3)]);
+			} else {
+				rows.push([new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1), new App.Arcology.Cell.Apartment(1)]);
+			}
+		}
+		return new App.Arcology.Section("apartments", rows);
+	}
+
+	function markets() {
+		if (location === "ravine") {
+			return new App.Arcology.Section("ravine-markets", [[new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1)]], true);
+		}
+		const rows = [];
+		if (location === "urban") {
+			rows.push([convertableCell(new App.Arcology.Cell.Apartment(1, 3), ["Apartment", "Market"]), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), convertableCell(new App.Arcology.Cell.Apartment(1, 3), ["Apartment", "Market"])]);
+			rows.push([new App.Arcology.Cell.Market(1), convertableCell(new App.Arcology.Cell.Market(1), ["Market", "Manufacturing"]), convertableCell(new App.Arcology.Cell.Market(1), ["Market", "Manufacturing"]), new App.Arcology.Cell.Market(1)]);
+		} else if (location === "rural") {
+			rows.push([new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1)]);
+		} else if (location === "marine") {
+			rows.push([new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), convertableCell(new App.Arcology.Cell.Manufacturing(1), ["Market", "Manufacturing"]), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1)]);
+		} else {
+			rows.push([new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1), new App.Arcology.Cell.Market(1)]);
+		}
+		return new App.Arcology.Section("markets", rows, true);
+	}
+
+	function manufacturing() {
+		const rows = [];
+		if (location === "urban") {
+			rows.push([new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1)]);
+		} else if (location === "rural") {
+			rows.push([new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1)]);
+		} else if (location === "marine") {
+			rows.push([convertableCell(new App.Arcology.Cell.Market(1), ["Market", "Manufacturing"]), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), convertableCell(new App.Arcology.Cell.Market(1), ["Market", "Manufacturing"])]);
+		} else {
+			rows.push([new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1), new App.Arcology.Cell.Manufacturing(1)]);
+		}
+		return new App.Arcology.Section("manufacturing", rows);
+	}
+
+	/**
+	 * @param {App.Arcology.Cell.BaseCell} cell
+	 * @param {Array<string>} conversions must include the initial cell
+	 */
+	function convertableCell(cell, conversions) {
+		cell.allowedConversions = conversions;
+		return cell;
+	}
 
 	return new App.Arcology.Building(sections);
 };
@@ -60,14 +131,15 @@ App.Arcology.defaultBuilding = function() {
  *
  * @type {string[]}
  */
-App.Arcology.sectionOrder = ["penthouse", "spire", "shops", "apartments", "markets", "manufacturing"];
+App.Arcology.sectionOrder = ["penthouse", "spire", "shops", "ravine-markets", "apartments", "markets", "manufacturing"];
 
 App.Arcology.Section = class extends App.Entity.Serializable {
 	/**
 	 * @param {string} id unique ID
 	 * @param {Array<Array<App.Arcology.Cell.BaseCell>>} rows
+	 * @param {boolean} groundLevel if the section the ground level, all lower layers are automatically in the basement
 	 */
-	constructor(id, rows) {
+	constructor(id, rows, groundLevel = false) {
 		super();
 		/**
 		 * @type {string}
@@ -77,6 +149,7 @@ App.Arcology.Section = class extends App.Entity.Serializable {
 		 * @type {Array<Array<App.Arcology.Cell.BaseCell>>}
 		 */
 		this.rows = rows;
+		this.groundLevel = groundLevel;
 	}
 
 	get width() {
@@ -105,15 +178,19 @@ App.Arcology.Section = class extends App.Entity.Serializable {
 		 * @returns {HTMLDivElement}
 		 */
 		function createCell(cell, rowIndex, cellIndex) {
-			const div = document.createElement("div");
-			div.classList.add("cell");
-			div.style.minWidth = `${elementWidth * cell.width}%`;
-			div.style.maxWidth = `${elementWidth * cell.width}%`;
+			const outerCell = document.createElement("div");
+			outerCell.classList.add("outerCell");
+			outerCell.style.minWidth = `${elementWidth * cell.width}%`;
+			outerCell.style.maxWidth = `${elementWidth * cell.width}%`;
 
-			div.classList.add(cell.owner === 1 ? cell.colorClass : "private");
-			div.append(cell.cellContent([index, rowIndex, cellIndex]));
+			const innerCell = document.createElement("div");
+			innerCell.classList.add("innerCell");
+			innerCell.classList.add(cell.owner === 1 ? cell.colorClass : "private");
+			innerCell.append(cell.cellContent([index, rowIndex, cellIndex]));
 
-			return div;
+			outerCell.append(innerCell);
+
+			return outerCell;
 		}
 
 		/**
@@ -209,11 +286,10 @@ App.Arcology.Building = class extends App.Entity.Serializable {
 	}
 
 	/**
-	 * @returns {HTMLDivElement}
+	 * @returns {DocumentFragment}
 	 */
 	render() {
-		const div = document.createElement("div");
-		div.classList.add("building");
+		const fragment = document.createDocumentFragment();
 
 		let maxWidth = 0;
 		this.sections.forEach(section => {
@@ -221,12 +297,24 @@ App.Arcology.Building = class extends App.Entity.Serializable {
 		});
 		const elementWidth = 100 / maxWidth;
 
+		const upperLevels = document.createElement("div");
+		upperLevels.classList.add("building");
+		const basement = document.createElement("div");
+		basement.classList.add("building", "basement");
+
+		let wrapper = upperLevels;
 		sortArrayByArray(App.Arcology.sectionOrder, this.sections, "id")
 			.forEach((section, index) => {
-				div.append(section.render(elementWidth, index));
+				wrapper.append(section.render(elementWidth, index));
+				if (section.groundLevel) {
+					// if there are multiple sections that are ground level the first (highest) section wins and all
+					// others are in the basement.
+					wrapper = basement;
+				}
 			});
 
-		return div;
+		fragment.append(upperLevels, basement);
+		return fragment;
 	}
 
 	/**
diff --git a/src/events/intro/initNationalities.tw b/src/events/intro/initNationalities.tw
index 0de2942a9e3..31bd50290d3 100644
--- a/src/events/intro/initNationalities.tw
+++ b/src/events/intro/initNationalities.tw
@@ -1,5 +1,10 @@
 :: init Nationalities [silently]
 
+<<set $building = App.Arcology.defaultBuilding($terrain)>>
+<<set _sellable = $building.findCells(cell => cell.canBeSold())>>
+<<set _random12 = jsRandomMany(_sellable, 12)>>
+<<run _random12.forEach(cell => {cell.owner = 0})>>
+
 <<if $secExpEnabled > 0>>
 	/* base vars */
 	<<set $SecExp = SecExpBase()>>
diff --git a/src/events/intro/terrainIntro.tw b/src/events/intro/terrainIntro.tw
index 95e6a589e84..634c1cdba70 100644
--- a/src/events/intro/terrainIntro.tw
+++ b/src/events/intro/terrainIntro.tw
@@ -39,26 +39,31 @@ Finally, a few Free Cities have been carved out from old world cities. Urban dec
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.green;High@@ ease of commerce with the old world.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.green;High@@ access to refugees and other desperate people.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.red;Low@@ cultural independence.
+<br>&nbsp;&nbsp;&nbsp;&nbsp;Unusually compact arcology with few manufacturing sectors.
 <br>[[Rural|Location Intro][$terrain = "rural"]]
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.yellow;High@@ minimum slave value and initial @@.yellow;bull market@@ for slaves.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate ease of commerce with the old world.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate access to refugees and other desperate people.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate cultural independence.
+<br>&nbsp;&nbsp;&nbsp;&nbsp;Widespread arcology with large amount of manufacturing.
 <br>[[Ravine|Location Intro][$terrain = "ravine"]]
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.yellow;High@@ minimum slave value and initial @@.yellow;bull market@@ for slaves.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.red;Low@@ ease of commerce with the old world.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.red;Very low@@ access to refugees and other desperate people.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.green;High@@ cultural independence.
+<br>&nbsp;&nbsp;&nbsp;&nbsp;The arcology is mostly being hidden inside the ravine leads to an unusual layout.
 <br>[[Marine|Location Intro][$terrain = "marine"]]
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate minimum slave value and initially balanced market for slaves.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate ease of commerce with the old world.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.red;Low@@ access to refugees and other desperate people.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.green;High@@ cultural independence.
+<br>&nbsp;&nbsp;&nbsp;&nbsp;Large amount of markets and and even an extra shop sector.
 <br>[[Oceanic|Intro Summary][$terrain = "oceanic"]]
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.yellow;High@@ minimum slave value and initial @@.yellow;bull market@@ for slaves.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Moderate ease of commerce with the old world.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.red;Very low@@ access to refugees and other desperate people.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;@@.green;Very high@@ cultural independence.
+<br>&nbsp;&nbsp;&nbsp;&nbsp;This unique location attracts the wealthy leading to initial luxury apartments.
 <br>&nbsp;&nbsp;&nbsp;&nbsp;Ensures access to slaves from all over the world and will not associate the arcology with a continent.
 <<if $showSecExp == 1>>
 	<br>Oceanic arcologies will not be subjects of attacks.
diff --git a/src/init/storyInit.tw b/src/init/storyInit.tw
index a36abd7abc2..aa41a10086c 100644
--- a/src/init/storyInit.tw
+++ b/src/init/storyInit.tw
@@ -109,10 +109,6 @@ You should have received a copy of the GNU General Public License along with thi
 
 <<run assistant.object()>>
 <<run repX(1000, "event")>>
-<<set $building = App.Arcology.defaultBuilding()>>
-<<set _sellable = $building.findCells(cell => cell.canBeSold())>>
-<<set _random12 = jsRandomMany(_sellable, 12)>>
-<<run _random12.forEach(cell => {cell.owner = 0})>>
 <<run setup.prostheticIDs.forEach(function(id) {
 	$prosthetics[id] = {amount: 0, research: 0};
 })>>
-- 
GitLab