code:
// @ts-nocheck
/* no-usedOnce */
App.SF.BC = function() {
	function InitClean() {
		delete V.SFMODToggle;
		delete V.securityForceActive;
		delete V.securityForceCreate;
		delete V.securityForceEventSeen;
	}

	function MainClean() {
		delete V.securityForceActive;
		delete V.securityForceRecruit;
		delete V.securityForceTrade;
		delete V.securityForceBooty;
		delete V.securityForceIncome;
		delete V.securityForceMissionEfficiency;
		delete V.securityForceProfitable;
		delete V.TierTwoUnlock;
		delete V.securityForceDepravity;
		delete V.SFAO;
		delete V.securityForceUpgradeTokenReset;
		delete V.securityForceUpgradeToken;
		delete V.securityForceGiftToken;
		delete V.securityForceRulesOfEngagement;
		delete V.securityForceFocus;
		delete V.securityForceAccountability;
		delete V.securityForceName;
		delete V.SubsidyActive;
		delete V.securityForceSubsidyActive;
	}

	function ColonelClean() {
		delete V.ColonelCore;
		delete V.securityForceColonelToken;
		delete V.securityForceColonelSexed;
		delete V.ColonelRelationship;
		delete V.securityForceSexedColonelToken;
	}

	function TradeShowClean() {
		delete V.OverallTradeShowAttendance;
		delete V.CurrentTradeShowAttendance;
		delete V.TradeShowIncome;
		delete V.TotalTradeShowIncome;
		delete V.TradeShowHelots;
		delete V.TotalTradeShowHelots;
	}

	function UnitsClean() {
		delete V.securityForceInfantryPower;
		delete V.securityForceArcologyUpgrades;
		delete V.securityForceVehiclePower;
		delete V.securityForceDronePower;
		delete V.securityForceStimulantPower;
		delete V.securityForceHeavyBattleTank;
		delete V.securityForceAircraftPower;
		delete V.securityForceSpacePlanePower;
		delete V.securityForceAC130;
		delete V.securityForceSatellitePower;
		delete V.securityForceGiantRobot;
		delete V.securityForceMissileSilo;
		delete V.securityForceAircraftCarrier;
		delete V.securityForceSubmarine;
		delete V.securityForceHeavyAmphibiousTransport;
		delete V.securityForcePersonnel;
		delete V.securityForceFortressZeppelin;
		delete V.securityForceHeavyTransport;
	}

	if (typeof V.SF !== "object") {
		if (V.securityForceEventSeen < 1) {
			V.securityForceActive = -1;
		} else {
			V.securityForceActive = 2;
		}
		V.SF = {Toggle: V.SFMODToggle, Active: V.securityForceActive};
		InitClean();
		if (V.securityForceName === undefined) {
			V.securityForceName = "the special force";
		}
		if (V.SF.Active >= 1) {
			Object.assign(V.SF, {
				Depravity: V.securityForceDepravity,
				Upgrade: V.securityForceUpgradeToken,
				Gift: V.securityForceGiftToken,
				UC: {Assign: V.SF.SpecOps, Lock: V.SF.SpecOpsLock},
				ROE: V.securityForceRulesOfEngagement,
				Target: V.securityForceFocus,
				Regs: V.securityForceAccountability,
				Lower: V.securityForceName,
			});
			MainClean();

			if (V.ColonelCore === undefined) {
				V.ColonelCore = "";
			}
			if (V.ColonelDiscussion === undefined) {
				V.ColonelDiscussion = 0;
			}
			if (V.ColonelSexed === undefined) {
				V.ColonelSexed = 0;
			}
			V.SF.Colonel = {
				Core: V.ColonelCore,
				Talk: V.securityForceColonelToken,
				Fun: V.securityForceColonelSexed,
				Status: V.ColonelRelationship
			};
			ColonelClean();

			if (V.TradeShowIncome === undefined) {
				V.TradeShowIncome = 0;
			}
			if (V.TotalTradeShowIncome === undefined) {
				V.TotalTradeShowIncome = 0;
			}
			if (V.TradeShowHelots === undefined) {
				V.TradeShowHelots = 0;
			}
			if (V.TotalTradeShowHelots === undefined) {
				V.TotalTradeShowHelots = 0;
			}
			V.SF.MercCon = {
				History: V.OverallTradeShowAttendance,
				CanAttend: V.CurrentTradeShowAttendance,
				Income: V.TradeShowIncome,
				Revenue: V.TotalTradeShowIncome,
				Menials: V.TradeShowHelots,
				TotalMenials: V.TotalTradeShowHelots,
				Mercs: 0,
				TotalMercs: 0
			};
			TradeShowClean();
			if (V.SF.MercCon.History > 0) {
				V.SF.MercCon.CanAttend = 1;
			}

			if (V.securityForceHeavyBattleTank === undefined) {
				V.securityForceHeavyBattleTank = 0;
			}
			if (V.securityForceSpacePlanePower === undefined) {
				V.securityForceSpacePlanePower = 0;
			}
			if (V.securityForceAC130 === undefined) {
				V.securityForceAC130 = 0;
			}
			if (V.securityForceSatellitePower === undefined) {
				V.securityForceSatellitePower = 0;
			}
			if (V.securityForceGiantRobot === undefined) {
				V.securityForceGiantRobot = 0;
			}
			if (V.securityForceMissileSilo === undefined) {
				V.securityForceMissileSilo = 0;
			}
			if (V.securityForceAircraftCarrier === undefined) {
				V.securityForceAircraftCarrier = 0;
			}
			if (V.securityForceSubmarine === undefined) {
				V.securityForceSubmarine = 0;
			}
			if (V.securityForceHeavyAmphibiousTransport === undefined) {
				V.securityForceHeavyAmphibiousTransport = 0;
			}

			V.SF.ArmySize = V.securityForcePersonnel;

			V.SF.SatLaunched = 0;

			V.SF.Squad = {
				Armoury: V.securityForceInfantryPower,
				Firebase: V.securityForceArcologyUpgrades,
				AV: V.securityForceVehiclePower,
				TV: V.securityForceVehiclePower,
				Drones: V.securityForceDronePower,
				Drugs: V.securityForceStimulantPower,
				PGT: V.securityForceHeavyBattleTank,
				AA: V.securityForceAircraftPower,
				TA: V.securityForceAircraftPower,
				SpacePlane: V.securityForceSpacePlanePower,
				GunS: V.securityForceAC130,
				Satellite: V.securityForceSatellitePower,
				GiantRobot: V.securityForceGiantRobot,
				MissileSilo: V.securityForceMissileSilo,
				AircraftCarrier: V.securityForceAircraftCarrier,
				Sub: V.securityForceSubmarine,
				HAT: V.securityForceHeavyAmphibiousTransport
			};
			UnitsClean();
		} else {
			App.SF.Init();
		}
	} else if (typeof V.SF === "object") {
		V.SF.FS = V.SF.FS || {};
		V.SF.FS.Tension = V.SF.FS.Tension || -1;

		if (V.SF.Toggle && V.SF.Active >= 1) {
			const FS_OPTIONS = App.SF.fsIntegration.list().all;
			for (let i = 0; i < FS_OPTIONS.length; i++) {
				V.SF.FS[FS_OPTIONS[i]] = V.SF.FS[FS_OPTIONS[i]] || {};
				V.SF.FS[FS_OPTIONS[i]].lv = V.SF.FS[FS_OPTIONS[i]].lv || 0;
				V.SF.FS[FS_OPTIONS[i]].gift = V.SF.FS[FS_OPTIONS[i]].gift || 0;
				delete V.SF.FS[FS_OPTIONS[i]].validOption;
			}

			V.SF.UC = V.SF.UC || {};
			V.SF.Depravity = V.SF.Depravity || 0;
			V.SF.Upgrade = V.SF.Upgrade || 0;
			V.SF.CreditsInvested = V.SF.CreditsInvested || 0;
			V.SF.Gift = V.SF.Gift || 0;
			V.SF.UC.Assign = V.SF.UC.Assign || 0;
			V.SF.UC.Lock = V.SF.UC.Lock || 0;
			V.SF.ROE = V.SF.ROE || "hold";
			V.SF.Target = V.SF.Target || "recruit";
			V.SF.Regs = V.SF.Regs || "strict";
			V.SF.Lower = V.SF.Lower || "the special force";

			V.SF.ArmySize = V.SF.ArmySize || 40;

			V.SF.Squad = V.SF.Squad || {};
			for (let i = 0; i < App.SF.upgrades.list('all').length; i++) {
				V.SF.Squad[App.SF.upgrades.list('all')[i]] = V.SF.Squad[App.SF.upgrades.list('all')[i]] || 0;
			}

			V.SF.SatLaunched = V.SF.SatLaunched || 0;

			V.SF.Colonel = V.SF.Colonel || {};
			V.SF.Colonel.Core = V.SF.Colonel.Core || "";
			V.SF.Colonel.Talk = V.SF.Colonel.Talk || 0;
			V.SF.Colonel.Fun = V.SF.Colonel.Fun || 0;
			V.SF.Colonel.Status = V.SF.Colonel.Status || 0;

			V.SF.MercCon = V.SF.MercCon || {};
			V.SF.MercCon.History = V.SF.MercCon.History || 0;
			V.SF.MercCon.CanAttend = V.SF.MercCon.CanAttend || 0;
			if (V.SF.MercCon.History >= 1) {
				V.SF.MercCon.CanAttend = -1;
			}
			V.SF.MercCon.Income = V.SF.MercCon.Income || 0;
			V.SF.MercCon.Revenue = V.SF.MercCon.Revenue || 0;
			V.SF.MercCon.Mercs = V.SF.MercCon.Mercs || 0;
			V.SF.MercCon.Menials = V.SF.MercCon.Menials || 0;
			V.SF.MercCon.TotalMenials = V.SF.MercCon.TotalMenials || 0;
			V.SF.MercCon.TotalMercs = V.SF.MercCon.TotalMercs || 0;

			if (typeof V.SF.Squad.Satellite === "object") {
				if (V.SF.Squad.Satellite.InOrbit > 0) {
					V.SF.SatLaunched = V.SF.Squad.Satellite.InOrbit; delete V.SF.Squad.Satellite.InOrbit;
				}
				V.SF.Squad.Satellite = V.SF.Squad.Satellite.lv;
			}

			delete V.SF.FS.upgrade; delete V.SF.UC.num;

			if (jsDef(V.choice)) {
				V.SF.Gift = V.choice;
			}

			if (V.Tour !== undefined) {
				V.SF.tour = V.Tour || 0;
			}

			if (V.SF.Squad.Troops) {
				V.SF.ArmySize = V.SF.Squad.Troops;
				delete V.SF.Squad.Troops;
			}

			if (V.SF.MercCon !== undefined) {
				if( V.SF.MercCon.View !== undefined) {
					delete V.SF.MercCon.View;
				}
				if (V.SF.MercCon.Helots !== undefined) {
					V.SF.MercCon.Menials = V.SF.MercCon.Helots;
					delete V.SF.MercCon.Helots;
				}
				if (V.SF.MercCon.TotalHelots !== undefined) {
					V.SF.MercCon.TotalMenials = V.SF.MercCon.TotalHelots;
					delete V.SF.MercCon.TotalHelots;
				}
			}

			if (V.SF.SpecOps !== undefined && V.SF.SpecOpsLock !== undefined) {
				V.SF.UC = {Assign: V.SF.SpecOps, Lock: V.SF.SpecOpsLock};
			}

			if (V.SFUC !== undefined) {
				V.SF.UC.num = V.SFUC || 0;
			}

			if (V.SpecOpsLock !== undefined) {
				V.SF.SpecOpsLock = V.SpecOpsLock;
			}

			if (V.SF.U !== undefined) {
				V.SF.Upgrade = V.SF.U || 0;
			}

			if (V.SF.WG !== undefined) {
				V.SF.Gift = V.SF.WG || 0;
			}

			if (V.SF.Depravity < 0) {
				V.SF.Depravity = 0;
			}

			if (V.SFUnit !== undefined) {
				if (V.SFUnit.AT !== undefined) {
					V.SFUnitTA = 0;
				}
				if (V.SFTradeShow !== undefined) {
					V.SF.MercCon = V.SFTradeShow;
				}
				delete V.SFTradeShow;
				if (V.SFColonel !== undefined) {
					V.SF.Colonel = V.SFColonel;
				}

				if (V.SF.Squad !== undefined && V.SF.Squad.Satellite !== undefined && V.SatLaunched !== undefined) {
					V.SF.Squad.Sat = {lv: V.SF.Squad.Satellite, InOrbit: V.SatLaunched};
					V.SF.Squad.Satellite = V.SF.Squad.Sat;
					delete V.SF.Squad.Sat;
					delete V.SatLaunched;
				}
			}
		} // closes: V.SF.Toggle && V.SF.Active >= 1
	}

	delete V.Tour; delete V.SFColonel; delete V.SFUnit;
	delete V.SF.tour; delete V.SF.Caps; delete V.SF.Size; delete V.choice;
	delete V.SF.Units; delete V.SpecOpsLock; delete V.SF.U; delete V.SF.WG;
	delete V.SF.Subsidy; delete V.SF.SpecOps; delete V.SF.SpecOpsLock; delete V.SFUC;

	if (V.SF.BadOutcome !== undefined) {
		delete V.SF.BadOutcome;
	}
	if (V.arcologies[0].SFRaid !== undefined) {
		delete V.arcologies[0].SFRaid;
	}
	if (V.arcologies[0].SFRaidTarget !== undefined) {
		delete V.arcologies[0].SFRaidTarget;
	}
	if (V.SF.Facility !== undefined) {
		delete V.SF.Facility;
	}

	if (V.SF.MWU !== undefined) {
		delete V.SF.MWU;
	}
	if (V.SF.Bonus !== undefined) {
		delete V.SF.Bonus;
	}

	InitClean();
	MainClean();
	ColonelClean();
	TradeShowClean();
	UnitsClean();

	if (V.week < 72 && V.SF.Active !== -1) { V.SF.Active = -1; }
};
/* usedOnce */


code:
:: Trick Shot Night [nobr]

<<set $nextButton = "Continue", $nextLink = "RIE Eligibility Check", $returnTo = "RIE Eligibility Check">>

<<setAssistantPronouns>>

<<if $PC.skill.warfare == -100>>
	<<set _shootChance = 5>>
<<elseif $PC.skill.warfare <= -75>>
	<<set _shootChance = 10>>
<<elseif $PC.skill.warfare <= -50>>
	<<set _shootChance = 15>>
<<elseif $PC.skill.warfare <= -25>>
	<<set _shootChance = 20>>
<<elseif $PC.skill.warfare == 0>>
	<<set _shootChance = 25>>
<<elseif $PC.skill.warfare <= 25>>
	<<set _shootChance = 45>>
<<elseif $PC.skill.warfare <= 50>>
	<<set _shootChance = 60>>
<<elseif $PC.skill.warfare <= 75>>
	<<set _shootChance = 85>>
<<elseif $PC.skill.warfare >= 100>>
	<<set _shootChance = 90>>
<</if>>

Despite your direct elevator, interaction with the majority of your security force is relatively scarce. Aside from mutually exchanged nods in the firebase and the occasional briefing, your $SF.Lower enjoy a degree of autonomy.

On a particularly lackadaisical evening, you find yourself alerted to a message alert by $assistant.name.
<<if $assistant.personality > 0>>
	"<<= properMaster()>>, a message from $SF.Lower." _HeA pauses before continuing. "It seems they're asking if you'd like to join their trick shot night."
<<else>>
	It informs you that $SF.Lower have sent a message asking you to join them at their trick shot night.
<</if>>

 <<link "Politely decline">>
	<<replace "#result">>
		You inform $SF.Lower that you aren't planning to attend. A short while later, you receive a message from them stating that their invitation is an open one and that you're welcome to join in another night.
	<</replace>>
<</link>>

<<if $cash < 50000>>

//You lack the necessary funds to attend.//
<<else>> /* cash >= 50000 */

<<link "Attend the trick shot night">>
		<<replace "#result">>
			You instruct $assistant.name to inform $SF.Lower that you will be attending their trick shot night, and after settling your affairs in the penthouse you head down to the firebase. The atmosphere in the firebase is casual, especially in comparison to the usual situations you meet them, though your security force still maintain some measure of decorum towards you as their employer. Eventually, you settle in at the table with a handful of $SF.Lower officers and turn your @@.yellowgreen;<<print cashFormat(50000)>>@@ into bullets. All that remains is to decide your strategy for the night.

			<<link "Play it safe">>
				<<replace "#bounty-result">>
					<<if random(1,100) > _shootChance>>
						Despite your attempts to mitigate risk and play the safest shots possible, it seems lady luck has conspired against you this evening. However, even when your last bullet is shot, your security force pitch you a few bullets to keep you in the game for the rest of the night. You may have lost most of your ¤, but it seems you've @@.green;made some friends.@@
						<<run repX(5000, "event")>>
						<<run cashX(-25000, "event")>>
					<<else>>
						While a careful eye for accuracy has buoyed you through the evening, ultimately lady luck is the decider in handing you the win in a number of close shots. Unfortunately your meticulous play limited your chance at a larger payout, and you only come away from the evening with @@.yellowgreen;<<print cashFormat(100000)>>@@ more than you arrived with and @@.green;the respect of your security force.@@
						<<run repX(5000, "event")>>
						<<run cashX(100000, "event")>>
					<</if>>
				<</replace>>
			<</link>>

			<<if random(1,100) < _shootChance>>

 <<link "Up the ante">>
					<<replace "#bounty-result">>
						<<if $arcologies[0].FSSupremacistLawME == 1>>
							<<set _race = $arcologies[0].FSSupremacistRace>>
						<<elseif $arcologies[0].FSSubjugationistLawME == 1>>
							<<set _races = setup.filterRacesLowercase.filter(race => race !== $arcologies[0].FSSubjugationistRace)>>
							<<set _race = _races.random()>>
						<</if>>
						<<set _genParam = {minAge: 25, maxAge: 35, ageOverridesPedoMode: 1, race: _race, disableDisability: 1}>>
						<<if $seeDicks != 100>>
							<<set _soldier = GenerateNewSlave("XX", _genParam)>>
						<<else>>
							<<set _soldier = GenerateNewSlave("XY", _genParam)>>
						<</if>>
						<<set _soldier.origin = "$He put $himself up as collateral at a trick shot game, and lost.">>
						<<set _soldier.career = "a soldier">>
						<<set _soldier.indentureRestrictions = 2>>
						<<set _soldier.indenture = 52>>
						<<set _soldier.devotion = random(45,60)>>
						<<set _soldier.trust = random(55,65)>>
						<<run setHealth(_soldier, jsRandom(60, 80), 0, undefined, 0, jsRandom(10, 30))>>
						<<set _soldier.muscles = 60>>
						<<if _soldier.weight > 130>>
							<<set _soldier.weight -= 100>>
							<<set _soldier.waist = random(-10,50)>>
						<</if>>
						<<set _soldier.anus = 0>>
						<<set _soldier.skill.anal = 0>>
						<<set _soldier.skill.whoring = 0>>
						<<set _soldier.skill.combat = 1>>
						<<set _soldier.accent = random(0,1)>>
						<<set _soldier.behavioralFlaw = "arrogant">>
						<<set _soldier.hLength = 1>>
						<<set _soldier.hStyle = "buzzcut">>
						<<set _soldier.clothes = "a military uniform">>
						<<run App.Utils.setLocalPronouns(_soldier)>>

						/* 000-250-006 */
						<<if $seeImages == 1>>
							<<if $imageChoice == 1>>

<<= SlaveArt(_soldier, 2, 0)>>

							<<else>>

<<= SlaveArt(_soldier, 2, 0)>>

							<</if>>
						<</if>>
						/* 000-250-006 */

						Some aggressive play and an eye for riling up your fellow players has resulted in an immense payout, and all but one of your adversaries have folded as the situation has escalated. The only player still in contention is a wily old mercenary, the veteran of $his fair share of battles on the battlefield and at the firing range. $He's short on bullets, however, and $he'll have to buy in with something else as collateral.

							<<link "A year of servitude">>
								<<set _soldier.clothes = "no clothing">>
								<<replace "#alive-result">>
									<<if random(1,100) > _shootChance>>
										For all your skillful maneuvering to reach this position, ultimately the win comes down to chance. This time, however, luck was not on your side. As the victor sweeps up $his spoils, the other security force clap you on the back and offer their condolences for your defeat. Though you may have lost your ¤, it seems you've @@.green;made some friends.@@
										<<run repX(5000, "event")>>
										<<run cashX(-50000, "event")>>
									<<else>>
										<<replace "#art-frame">>

											/* 000-250-006 */
											<<if $seeImages == 1>>
												<<if $imageChoice == 1>>

<<= SlaveArt(_soldier, 2, 0)>>

												<<else>>

<<= SlaveArt(_soldier, 2, 0)>>

												<</if>>
											<</if>>
											/* 000-250-006 */

										<</replace>>
										For all your skillful maneuvering to reach this position, ultimately the win comes down to chance. This time, however, luck has rendered you the victor. A silence falls over the room as the result is declared, but after some time your opponent breaks the hush by joking that life as your slave is probably easier than fighting for $arcologies[0].name. After some awkward laughter the night continues, and at the end your former mercenary joins you on your trip back to the penthouse to submit to processing and to begin $his new life as your sexual servant. $He's not young, but $he's tough and not distrusting of you due to $his service in $SF.Lower.

										<<includeDOM App.UI.newSlaveIntro(_soldier)>>
									<</if>>
									<<= IncreasePCSkills('warfare', 1)>>
								<</replace>>
							<</link>>

 <<link "Dock $his wages">>
								<<replace "#alive-result">>
									<<if random(1,100) > _shootChance>>
										For all your skillful maneuvering to reach this position, ultimately the win comes down to chance. This time, however, luck was not on your side. As the victor sweeps up $his spoils, the other security force members clap you on the back and offer their condolences for your defeat. Though you may have lost your ¤, it seems you've @@.green;made some friends.@@
										<<run repX(5000, "event")>>
										<<run cashX(-50000, "event")>>
									<<else>>
										For all your skillful maneuvering to reach this position, ultimately the win comes down to chance. This time, however, luck has rendered you the victor. Your opponent accepts $his defeat with grace and jokes to $his comrades that $he'll be fighting in $his underwear for the next few months, and their uproar of laughter fills the room. Though you take the lion's share of the ¤, your security force also @@.green;had a good time fraternizing with you.@@
										<<run repX(10000, "event")>>
										<<run cashX(50000, "event")>>
									<</if>>
									<<= IncreasePCSkills('warfare', 1)>>
								<</replace>>
							<</link>>

					<</replace>>
				<</link>>
			<</if>>

		<</replace>>
	<</link>> // It will cost <<print cashFormat(50000)>> to participate in the trick shot night.//
<</if>>

repo_name: Welptard/fc

license: mit


code:
:: Upgrades [nobr]

<<set _upgradeDiv = 1.65>>
<<set _fullyUpgraded = []>>
Which facility or equipment do you wish to upgrade this week?

<<if $SF.Squad.Firebase < App.SF.upgrades.currentUnitMax('Firebase')>>
	<<set _cF = App.SF.UpgradeCost(125000/_upgradeDiv,$SF.Squad.Firebase)>>
	<<if $cash >= _cF>>

		[[Upgrade Firebase|Firebase][$SF.Upgrade = 1, $SF.Squad.Firebase++, $SF.CreditsInvested += (_cF), cashX(forceNeg(_cF), "specialForcesCap")]]
	<<else>>
		//Cannot afford to upgrade the Firebase.//
	<</if>>
	//Costs @@.red;<<print cashFormat(_cF)>>@@//  <<print App.SF.progress($SF.Squad.Firebase)>>

<<elseif $SF.Squad.Firebase === 10>>
	<<set _fullyUpgraded.push('Firebase')>>
<</if>>

<<if $SF.Squad.Armoury < App.SF.upgrades.currentUnitMax('Armoury')>>
	<<set _cA = App.SF.UpgradeCost(40000/_upgradeDiv,$SF.Squad.Armoury)>>
	<<if $cash >= _cA>>
		[[Upgrade Armory|Firebase][$SF.Upgrade = 1, $SF.Squad.Armoury++, $SF.CreditsInvested += (_cA), cashX(forceNeg(_cA), "specialForcesCap")]]
	<<else>>
		//Cannot afford to upgrade the Armory.//
	<</if>>
	//Costs @@.red;<<print cashFormat(_cA)>>@@//  <<print App.SF.progress($SF.Squad.Armoury)>>

<<elseif $SF.Squad.Armoury === 10>>
	<<set _fullyUpgraded.push('Armory')>>
<</if>>

<<if $SF.Squad.Drugs < App.SF.upgrades.currentUnitMax('Drugs')>>
	<<set _cDrugs = App.SF.UpgradeCost(40000/_upgradeDiv,$SF.Squad.Drugs)>>
	<<if $cash >= _cDrugs>>
		[[Upgrade Drug Lab|Firebase][$SF.Upgrade = 1, $SF.Squad.Drugs++, $SF.CreditsInvested += (_cDrugs), cashX(forceNeg(_cDrugs), "specialForcesCap")]]
	<<else>>
			//Cannot afford to upgrade the Drug Lab.//
	<</if>>
	//Costs @@.red;<<print cashFormat(_cDrugs)>>@@//  <<print App.SF.progress($SF.Squad.Drugs)>>

<<elseif $SF.Squad.Drugs === 10>>
	<<set _fullyUpgraded.push('Drug Lab')>>
<</if>>

<<if $SF.Squad.Firebase >= 2 && $SF.Squad.Drones < App.SF.upgrades.currentUnitMax('Drones')>>
	<<set _cDrones = App.SF.UpgradeCost(45000/_upgradeDiv,$SF.Squad.Drones)>>
	<<if $cash >= _cDrones>>
		[[Upgrade Drone Bay|Firebase][$SF.Upgrade = 1, $SF.Squad.Drones++, $SF.CreditsInvested += (_cDrones), cashX(forceNeg(_cDrones), "specialForcesCap")]]
	<<else>>
		//Cannot afford to upgrade the Drone Bay.//
	<</if>>
	//Costs @@.red;<<print cashFormat(_cDrones)>>@@//  <<print App.SF.progress($SF.Squad.Drones)>>

<<elseif $SF.Squad.Drones === 10>>
	<<set _fullyUpgraded.push('Drone Bay')>>
<</if>>

<<if App.SF.unlocked.garage()>>
''Garage''

	<<if $SF.Squad.AV < App.SF.upgrades.currentUnitMax('AV')>>
		<<set _cAV = App.SF.UpgradeCost(60000/_upgradeDiv,$SF.Squad.AV)>>
		<<if $cash >= _cAV>>
			[[Upgrade Attack Vehicle Fleet|Firebase][$SF.Upgrade = 1, $SF.Squad.AV++, $SF.CreditsInvested += (_cAV), cashX(forceNeg(_cAV), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade the Attack Vehicle Fleet.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cAV)>>@@//  <<print App.SF.progress($SF.Squad.AV)>>

	<<elseif $SF.Squad.AV === 10>>
		<<set _fullyUpgraded.push('Attack Vehicle Fleet')>>
	<</if>>

	<<if $SF.Squad.TV < App.SF.upgrades.currentUnitMax('TV')>>
		<<set _cTV = App.SF.UpgradeCost(60000/_upgradeDiv,$SF.Squad.TV)>>
		<<if $cash >= _cTV>>
			[[Upgrade Transport Vehicle Fleet|Firebase][$SF.Upgrade = 1, $SF.Squad.TV++, $SF.CreditsInvested += (_cTV), cashX(forceNeg(_cTV), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Transport Vehicle Fleet.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cTV)>>@@//  <<print App.SF.progress($SF.Squad.TV)>>

	<<elseif $SF.Squad.TV === 10>>
		<<set _fullyUpgraded.push('Transport Vehicle Fleet')>>
	<</if>>

	<<set _PGTU = App.SF.upgrades.currentUnitMax('PGT')>>
	<<if $SF.Squad.PGT < _PGTU>>
		<<set _cPGT = App.SF.UpgradeCost(735000/_upgradeDiv,$SF.Squad.PGT)>>
		<<if $cash >= _cPGT>>
			[[Upgrade Prototype Goliath tank|Firebase][$SF.Upgrade = 1, $SF.Squad.PGT++, $SF.CreditsInvested += (_cPGT), cashX(forceNeg(_cPGT), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Prototype Goliath Tank.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cPGT)>>@@//  <<print App.SF.progress($SF.Squad.PGT)>>

	<<elseif $SF.Squad.PGT === _PGTU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.PGT)>>

	<<elseif $SF.Squad.PGT === _PGTU>>
		<<set _fullyUpgraded.push('Prototype Goliath Tank')>>
	<</if>>

<</if>> /*Closes garage.*/

<<if App.SF.unlocked.hangar()>>''Hangar''

	<<if $SF.Squad.AA < App.SF.upgrades.currentUnitMax('AA')>>
		<<set _cAA = App.SF.UpgradeCost(70000/_upgradeDiv,$SF.Squad.AA)>>
		<<if $cash >= _cAA>>
			[[Upgrade Attack Aircraft Fleet|Firebase][$SF.Upgrade = 1, $SF.Squad.AA++, $SF.CreditsInvested += (_cAA), cashX(forceNeg(_cAA), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Attack Aircraft Fleet.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cAA)>>@@//  <<print App.SF.progress($SF.Squad.AA)>>

	<<elseif $SF.Squad.AA === 10>>
		<<set _fullyUpgraded.push('Attack Aircraft Fleet')>>
	<</if>>

	<<if $SF.Squad.TA < App.SF.upgrades.currentUnitMax('TA')>>
		<<set _cTA = App.SF.UpgradeCost(70000/_upgradeDiv,$SF.Squad.TA)>>
		<<if $cash >= _cTA>>
			[[Upgrade Transport Aircraft Fleet|Firebase][$SF.Upgrade = 1, $SF.Squad.TA++, $SF.CreditsInvested += (_cTA), cashX(forceNeg(_cTA), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade the Transport Aircraft Fleet.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cTA)>>@@//  <<print App.SF.progress($SF.Squad.TA)>>

	<<elseif $SF.Squad.TA === 10>>
		<<set _fullyUpgraded.push('Transport Aircraft Fleet')>>
	<</if>>

	<<set _SPU = App.SF.upgrades.currentUnitMax('SpacePlane')>>
	<<if $SF.Squad.SpacePlane < _SPU>>
		<<set _cSP = App.SF.UpgradeCost(250000/_upgradeDiv,$SF.Squad.SpacePlane)>>
		<<if $cash >= _cSP>>
			[[Upgrade Spaceplane|Firebase][$SF.Upgrade = 1, $SF.Squad.SpacePlane++, $SF.CreditsInvested += (_cSP), cashX(forceNeg(_cSP), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade the Spaceplane.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cSP)>>@@// <<print App.SF.progress($SF.Squad.SpacePlane)>>

	<<elseif $SF.Squad.SpacePlane === _SPU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.SpacePlane)>>

	<<elseif $SF.Squad.SpacePlane === _SPU>>
		<<set _fullyUpgraded.push('Spaceplane')>>
	<</if>>

	<<set _GunSU = App.SF.upgrades.currentUnitMax('GunS')>>
	<<if $SF.Squad.GunS < _GunSU>>
		<<set _cGunS = App.SF.UpgradeCost(350000/_upgradeDiv,$SF.Squad.GunS)>>
		<<if $cash >= _cGunS>>
			[[Upgrade Gunship|Firebase][$SF.Upgrade = 1, $SF.Squad.GunS++, $SF.CreditsInvested += (_cGunS), cashX(forceNeg(_cGunS), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Gunship.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cGunS)>>@@// <<print App.SF.progress($SF.Squad.GunS)>>

	<<elseif $SF.Squad.GunS === _GunSU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.GunS)>>

	<<elseif $SF.Squad.GunS === _GunSU>>
		<<set _fullyUpgraded.push('Gunship')>>
	<</if>>

<</if>> /*Closes hangar.*/

<<if App.SF.unlocked.launchBay()>>''Launch Bay''

	<<set _SatU = App.SF.upgrades.currentUnitMax('Satellite')>>
	<<if $SF.Squad.Satellite < _SatU && $SF.SatLaunched < 1>>
		<<set _cSat = App.SF.UpgradeCost(525000/_upgradeDiv,$SF.Squad.Satellite)>>
		<<if $cash >= _cSat>>
			[[Upgrade Satellite|Firebase][$SF.Upgrade = 1, $SF.Squad.Satellite++, $SF.CreditsInvested += (_cSat), cashX(forceNeg(_cSat), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Satellite.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cSat)>>@@// <<print App.SF.progress($SF.Squad.Satellite)>>

	<<elseif $SF.Squad.Satellite === _SatU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.Satellite)>>

	<<else>>
		<<set _fullyUpgraded.push('Satellite')>>
	<</if>>

	<<if $terrain !== "oceanic">>

		<<set _GRU = App.SF.upgrades.currentUnitMax('GiantRobot')>>
		<<if $SF.Squad.GiantRobot < _GRU>>
			<<set _cGR = App.SF.UpgradeCost(550000/_upgradeDiv,$SF.Squad.GiantRobot)>>
			<<if $cash >= _cGR>>
				[[Upgrade Giant Robot|Firebase][$SF.Upgrade = 1, $SF.Squad.GiantRobot++, $SF.CreditsInvested += (_cGR), cashX(forceNeg(_cGR), "specialForcesCap")]]
			<<else>>
				//Cannot afford to upgrade the Giant Robot.//
			<</if>>
			//Costs @@.red;<<print cashFormat(_cGR)>>@@// <<print App.SF.progress($SF.Squad.GiantRobot)>>

		<<elseif $SF.Squad.GiantRobot === _GRU && $PC.skill.warfare < 75>>
			//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.GiantRobot)>>

		<<else>>
			<<set _fullyUpgraded.push('Giant Robot')>>
		<</if>>

		<<set _MSU = App.SF.upgrades.currentUnitMax('MissileSilo')>>
		<<if $SF.Squad.MissileSilo < _MSU>>
			<<set _cMS = App.SF.UpgradeCost(565000/_upgradeDiv,$SF.Squad.MissileSilo)>>
			<<if $cash >= _cMS>>
				[[Upgrade Cruise Missile|Firebase][$SF.Upgrade = 1, $SF.Squad.MissileSilo++, $SF.CreditsInvested += (_cMS), cashX(forceNeg(_cMS), "specialForcesCap")]]
			<<else>>
				//Cannot afford to upgrade Cruise Missile.//
			<</if>>
			//Costs @@.red;<<print cashFormat(_cMS)>>@@// <<print App.SF.progress($SF.Squad.MissileSilo)>>

		<<elseif $SF.Squad.MissileSilo === _MSU && $PC.skill.warfare < 75>>
			//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.MissileSilo)>>

		<<else>>
			<<set _fullyUpgraded.push('Cruise Missile')>>
		<</if>>

	<</if>>
<</if>> /*Closes Launch Bay.*/

<<if App.SF.unlocked.navalYard()>>''Naval Yard''

	<<set _ACU = App.SF.upgrades.currentUnitMax('AircraftCarrier')>>
	<<if $SF.Squad.AircraftCarrier < _ACU>>
		<<set _cAC = App.SF.UpgradeCost(650000/_upgradeDiv,$SF.Squad.AircraftCarrier)>>
		<<if $cash >= _cAC>>
			[[Upgrade Aircraft Carrier|Firebase][$SF.Upgrade = 1, $SF.Squad.AircraftCarrier++, $SF.CreditsInvested += (_cAC), cashX(forceNeg(_cAC), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Aircraft Carrier.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cAC)>>@@// <<print App.SF.progress($SF.Squad.AircraftCarrier)>>

	<<elseif $SF.Squad.AircraftCarrier === _ACU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.AircraftCarrier)>>

	<<else>>
		<<set _fullyUpgraded.push('Aircraft Carrier')>>
	<</if>>

	<<set _SubU = App.SF.upgrades.currentUnitMax('Sub')>>
	<<if $SF.Squad.Sub < _SubU>>
		<<set _cSub = App.SF.UpgradeCost(700000/_upgradeDiv,$SF.Squad.Sub)>>
		<<if $cash >= _cSub>>
			[[Upgrade Submarine|Firebase][$SF.Upgrade = 1, $SF.Squad.Sub++, $SF.CreditsInvested += (_cSub), cashX(forceNeg(_cSub), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Submarine//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cSub)>>@@// <<print App.SF.progress($SF.Squad.Sub)>>
	<<elseif $SF.Squad.Sub === _SubU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.Sub)>>
	<<else>>
		<<set _fullyUpgraded.push('Submarine')>>
	<</if>>

	<<set _HATU = App.SF.upgrades.currentUnitMax('HAT')>>
	<<if $SF.Squad.HAT < _HATU>>
		<<set _cHAT = App.SF.UpgradeCost(665000/_upgradeDiv,$SF.Squad.HAT)>>
		<<if $cash >= _cHAT>>
			[[Upgrade Amphibious Transport|Firebase][$SF.Upgrade = 1, $SF.Squad.HAT++, $SF.CreditsInvested += (_cHAT), cashX(forceNeg(_cHAT), "specialForcesCap")]]
		<<else>>
			//Cannot afford to upgrade Amphibious Transport.//
		<</if>>
		//Costs @@.red;<<print cashFormat(_cHAT)>>@@// <<print App.SF.progress($SF.Squad.HAT)>>
	<<elseif $SF.Squad.HAT === _HATU && $PC.skill.warfare < 75>>
		//Your warfare skill is not high enough unlock the next upgrade.// <<print App.SF.progress($SF.Squad.HAT)>>

	<<else>>
		<<set _fullyUpgraded.push('Amphibious Transport')>>
	<</if>>

<</if>> /*Closes Naval Yard.*/

<<if _fullyUpgraded.length > 0>>
//The following units are fully upgraded: <<= _fullyUpgraded>>//. <</if>>


code:
:: WC [nobr]

<<set _Env = App.SF.env(), _size = App.SF.upgrades.total(), _colonelTalkTensionRuction = $SF.FS.Tension !== -1 ? 5 : 0>>

<<switch _Env>>
<<case 4>>
	<<set _EnvCash2 = 450,_EnvCash3 = 200,_EnvCash4 = 100>>
<<case 3>>
	<<set _EnvCash2 = 500,_EnvCash3 = 250,_EnvCash4 = 150>>
<<case 2>>
	<<set _EnvCash2 = 550,_EnvCash3 = 300,_EnvCash4 = 200>>
<</switch>>

<<if $SF.Gift === 0>>
	<<if $SF.Colonel.Talk + $SF.Colonel.Fun === 0>>
		The Colonel looks down a list on her tablet. "There's some things we can do to help you out, boss.

We've had some good prizes turn up, that's made us some extra money we could turn over.
	<<else>>

He looks down a list on his tablet. "<<= properTitle()>>, how can $SF.Lower help you this week?

 <<= capFirstChar($SF.Lower || "the special force")>> can spare some profits from our recent operations.
	<</if>>
	| <<link "Request cash" "Firebase">>
		<<run cashX(App.SF.weeklyGift(1), "specialForcesCap")>>
	<</link>>

	<<if $rep < 20000>>
		<<if $SF.Colonel.Talk + $SF.Colonel.Fun === 0>>

If you want we could throw a quick military parade, get the people feeling extra patriotic.
		<<else>>

We can set some units aside for a ceremonial march through the arcology.
		<</if>>
		| <<link "Request military parade" "Firebase">>
			<<run repX(App.SF.weeklyGift(2), "specialForces")>>
		<</link>>
	<</if>>

	<<if $arcologies[0].prosperity < $AProsperityCap>>
		<<if $SF.Colonel.Talk + $SF.Colonel.Fun === 0>>

Or we could hit some businesses that rival the ones in $arcologies[0].name with some sabotage.
		<<else>>

Or we can target rival businesses for sabotage.
		<</if>>
		| <<link "Request sabotage" "Firebase">>
			<<set _GoodWords2 = App.SF.weeklyGift(3)>>
			<<if $arcologies[0].prosperity + _GoodWords2 * 0.8 > $AProsperityCap>>
				<<set $arcologies[0].prosperity = $AProsperityCap>>
			<<else>>
				<<set $arcologies[0].prosperity += Math.ceil(_GoodWords2 * 0.8)>>
			<</if>>
		<</link>>
	<</if>>
<</if>>

<<if $SF.Colonel.Talk + $SF.Colonel.Fun === 0>>

"If you need me for anything else, let me know."

	<<if $SF.Colonel.Status >= 25>>

<<link "Walk with The Colonel on the surface" "Firebase">>
			<<set $SF.Colonel.Talk = 1, $SF.Colonel.Status += 2, $SF.FS.Tension -= _colonelTalkTensionRuction>>
		<</link>>
	<</if>>

<<link "Talk in $SF.Lower's HQ">>
		<<replace "#result2">>

What do you want to do with The Colonel in the HQ?

<<link "Talk" "Firebase">>
			<<set $SF.Colonel.Talk = 2, $SF.Colonel.Status += 3, $SF.FS.Tension -= _colonelTalkTensionRuction>>
		<</link>>

<<link "Learn" "Firebase">>
			<<set $SF.Colonel.Talk = 3,$SF.Colonel.Status += 1, $SF.FS.Tension -= _colonelTalkTensionRuction>>
		<</link>>

		<<if $SF.Colonel.Status >= 45>>

			<<link "Have some fun">>
				<<replace "#result3">>

				<<set $SF.Colonel.Fun = 1, $SF.Colonel.Status += 3, $SF.FS.Tension -= _colonelTalkTensionRuction>>

Where should this fun take place?
				<<link "Go back" "Firebase">>
					<<set $SF.Colonel.Fun = 0, $SF.Colonel.Talk = 0,$SF.Colonel.Status -= 3, $SF.FS.Tension += _colonelTalkTensionRuction>>
				<</link>>

<<link "In private">>
					<<replace "#result4">>

Which orifice do you wish to target?
					<<link "Go back" "Firebase">> <</link>>

<<link "Pussy">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "Ass">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "Both pussy and ass">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 2>>
					<</link>>

<<link "Mouth">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "All three holes">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 3>>
					<</link>>

					<</replace>>
				<</link>>

<<link "On The Colonel's throne">>
					<<replace "#result4">>

Which orifice do you wish to target?
					<<link "Go back" "Firebase">> <</link>>

<<link "Pussy">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "Ass">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "Both pussy and ass">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 2>>
					<</link>>

<<link "Mouth">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 1>>
					<</link>>

<<link "All three holes">>
						<<replace "#result6">>
						<<include "SFColonelSexDec">>
						<</replace>>
						<<set $SF.Colonel.Fun += 3>>
					<</link>>

					<</replace>>
				<</link>>

			<</replace>>
			<</link>>
		<</if>> /*Closes fun*/

		<</replace>>
	<</link>> /*Closes talk*/

<</if>> /*Closes spend time with The Colonel*/

<<if $SF.Colonel.Talk === 1>>

You ask The Colonel if she would like to stretch her legs up on the surface. It doesn't take much effort for her to agree.
	<<if $PC.skill.warfare >= 100 && $PC.career == "mercenary">>
		Your mastery of wet work and prior experience in a PMC satisfies The Colonel that between you<<if _S.Bodyguard>>, _S.Bodyguard.slaveName,<</if>> and her, there should be little threat to walking around the arcology. Being able to see and interact with the arcology owner directly maintains the false idea that you're just like one of them while also giving them an increased opportunity to try gaining your favor.
		<<run repX(10, "specialForces"), cashX(_EnvCash2, "specialForces")>>
	<<elseif $PC.skill.warfare >= 100>>
		Your mastery of wet work satisfies The Colonel that you only need two soldiers <<if _S.Bodyguard>> plus _S.Bodyguard.slaveName<</if>> to walk safely around the arcology. Being able to see and interact with the arcology owner directly maintains the false idea that you're just like one of them while also giving them an increased opportunity to try gaining your favor.
		<<run repX(5, "specialForces"), cashX(_EnvCash3, "specialForces")>>
	<<elseif $PC.skill.warfare >= 60>>
		With some expertise in warfare, The Colonel believes <<if _S.Bodyguard>>with _S.Bodyguard.slaveName <</if>>you only need a squad of armed soldiers for a walk through the arcology.
	<<elseif $PC.skill.warfare >= 30>>
		As you have some skill in warfare, The Colonel believes<<if _S.Bodyguard>> with _S.Bodyguard.slaveName<</if>> you only need two full squads of armed soldiers for a walk around the arcology.
	<<elseif $PC.skill.warfare >= 10>>
		Your minor skill in warfare convinces The Colonel that <<if _S.Bodyguard>>in addition to _S.Bodyguard.slaveName, <</if>>you need two full squads of armed soldiers and an armored car escort for a simple walk around the arcology.
	<<else>>
		Your complete lack of combat skill convinces The Colonel that <<if _S.Bodyguard>>in addition to _S.Bodyguard.slaveName, <</if>>you need two full squads of armed soldiers, an armored car escort, and a sniper overwatch for a simple walk around the arcology.
	<</if>>

As you make your way through the arcology you stop at a
	<<if $arcologies[0].FSPaternalist != "unset">>
		paternalist shop, <<if $SF.Colonel.Core == "cruel">>earning a sneer from The Colonel<<else>>helping The Colonel select some luxurious and relaxing slave treatments<</if>>.
	<<elseif $arcologies[0].FSPastoralist != "unset">>
		pastoralist shop, helping The Colonel select a more comfortable breast pump.
	<<else>>
		shop that catches The Colonel's eye.
	<</if>>
	<<if $PC.skill.slaving >= 100 && $PC.career == "slaver">>
		Your mastery and extensive history of slaving allows you to assist The Colonel greatly. The shop owner is so impressed by your understanding of slavery that she asks you for some advice. Before you leave, you manage to pass on a few tips, helping the business with future customers.
		<<if $arcologies[0].prosperity < $AProsperityCap>>
			<<set $arcologies[0].prosperity++>>
		<</if>>
	<<elseif $PC.skill.slaving >= 100>>
		Your mastery and extensive history of slaving allows you to assist The Colonel greatly. The shop owner is so impressed by your understanding of slavery that she asks you for some advice. Before you leave, you manage to pass on a few tips, helping the business with future customers.
		<<if $arcologies[0].prosperity < $AProsperityCap>>
			<<set $arcologies[0].prosperity++>>
		<</if>>
	<<elseif $PC.skill.slaving >= 60>>
		Your expertise in slavery allows you to help The Colonel decide what to buy for her main slave.
	<<elseif $PC.skill.slaving >= 30>>
		Your moderate skill in slavery makes you somewhat helpful to The Colonel in deciding what to buy for her main slave.
	<<elseif $PC.skill.slaving >= 10>>
		Your basic skill level of slavery doesn't allow you to help The Colonel at all.
	<<elseif $PC.skill.slaving < 10>>
		Your total lack of slavery skill (which is very unusual and very concerning for an arcology owner) means that you are of little to no help or even a hindrance. The shopkeeper notices your complete ineptitude, and as soon as you've left the rumor mill begins.
		<<run repX(-20, "PCactions")>>
	<</if>>

Soon the entourage heads back to the HQ of $SF.Lower.
	<<if random(1,100) > 50>>
		Along the route you see a homeless citizen with a serious injury begging for help.
		<<if $PC.skill.medicine >= 100 && $PC.career == "medicine">>
			Your expertise in surgery ensures that the citizen receives the best care they'll ever experience in their life. They are so grateful that they are more than happy to try and compensate your time. Word quickly spreads of the kindly medically trained arcology owner who took the time to heal a citizen, providing confidence to the rest of the citizens.
			<<run repX(10, "specialForces")>>
			<<run cashX(_EnvCash4, "specialForces")>>
		<<elseif $PC.skill.medicine >= 100>>
			Your expertise in surgery ensures that the citizen receives the best care they'll ever experience in their life. Word quickly spreads of the kindly arcology owner who took the time to heal a citizen.
			<<run repX(5, "specialForces")>>
		<<elseif $PC.skill.medicine >= 60>>
			Your proficiency in surgery allows you to properly close their wound with minimal trauma to the patient.
		<<elseif $PC.skill.medicine >= 30>>
			Your moderate surgical skill ensures that you can close the citizen's wound, though not without likely scarring.
		<<elseif $PC.skill.medicine >= 10>>
			Your basic surgical skill in medicine is sufficient only to stabilize the citizen's wounds before medical assistance arrives.
		<<else>>
			Your total lack of surgical skill causes the death of the citizen through repeated medical blunders.
			<<set $arcologies[0].prosperity -= .25>>
		<</if>>
	<</if>>
<<elseif $SF.Colonel.Talk === 2>>

You and The Colonel talk over some $PC.refreshment, where she ends up talking about her past. You learn a little more about her.
	<<switch random(1,6)>>
	<<case 1>>
		<<= IncreasePCSkills(['medicine', 'trading', 'slaving'], 1)>>
	<<case 2>>
		<<= IncreasePCSkills(['trading', 'slaving', 'engineering'], 1)>>
	<<case 3>>
		<<= IncreasePCSkills(['slaving', 'engineering', 'hacking'], 1)>>
	<<case 4>>
		<<= IncreasePCSkills(['engineering', 'hacking', 'warfare'], 1)>>
	<<case 5>>
		<<= IncreasePCSkills(['hacking', 'warfare', 'medicine'], 1)>>
	<<case 6>>
		<<= IncreasePCSkills(['warfare', 'medicine', 'trading'], 1)>>
	<</switch>>
<<elseif $SF.Colonel.Talk === 3>>

"Sure boss, I can use a break from all of this," she laughs. The Colonel tells a story about one time when she
	<<switch random(1,6)>>
	<<case 1>>
		used field medicine to save another merc's life, teaching you some medical procedures in the process.
		<<= IncreasePCSkills('medicine', 5)>>
	<<case 2>>
		haggled for necessary gear with a stingy quartermaster, teaching you how to get what you want from traders.
		<<= IncreasePCSkills('trading', 5)>>
	<<case 3>>
		found a load of human chattel in a raid and had to manage them before they could later be unloaded, teaching you how to better care for your slaves.
		<<= IncreasePCSkills('slaving', 5)>>
	<<case 4>>
		was responsible for rebuilding a fort she had seized, teaching you how to better manage construction in your arcology.
		<<= IncreasePCSkills('engineering', 5)>>
	<<case 5>>
		was forced to hack her way out of a trap, teaching you how to better penetrate digital security.
		<<= IncreasePCSkills('hacking', 5)>>
	<<case 6>>
		fought off an entire battalion with only a small squad, teaching you how to think tactically in battle.
		<<= IncreasePCSkills('warfare', 5)>>
	<</switch>>
<</if>>


code:
:: editSF [nobr]

<>

<<set _max = App.SF.upgrades.max(), _T1 = App.SF.unlocked.secondTier(), _size = App.SF.upgrades.total(),
$nextButton = "Back to $SF.Lower's Firebase", $nextLink = "Firebase", _options = new App.UI.OptionsGroup()>>

__Upgrades__: _size/_max(<<= (_size/_max).toFixed(2)>>%)
<<run _options.addOption("''Firebase: '' (current max <<= App.SF.upgrades.currentUnitMax('Firebase')>>)", "Firebase", V.SF.Squad).showTextBox()>>
<<run _options.addOption("''Armoury: '' (current max <<= App.SF.upgrades.currentUnitMax('Armoury')>>)", "Armoury", V.SF.Squad).showTextBox()>>
<<run _options.addOption("''Drugs: '' (current max <<= App.SF.upgrades.currentUnitMax('Drugs')>>)", "Drugs", V.SF.Squad).showTextBox()>>

<<if $SF.Squad.Firebase >= 2>>
	<<run _options.addOption("''Drones: '' (current max <<= App.SF.upgrades.currentUnitMax('Drones')>>)", "Drones", V.SF.Squad).showTextBox()>>
<</if>>

<<if App.SF.unlocked.garage()>>
	<<run _options.addOption("''Garage:''
  ''Attack Vehicles: '' (current max <<= App.SF.upgrades.currentUnitMax('AV')>>)", "AV", V.SF.Squad).showTextBox()>>
	<<run _options.addOption("  ''Transport Vehicles: '' (current max <<= App.SF.upgrades.currentUnitMax('TV')>>)", "TV", V.SF.Squad).showTextBox()>>
	<<if _T1>>
		<<run _options.addOption(" ''Prototype Goliath Tank: '' (current max <<= App.SF.upgrades.currentUnitMax('PGT')>>)", "PGT", V.SF.Squad).showTextBox()>>
	<</if>>
<</if>>

<<if App.SF.unlocked.hangar()>>
	<<run _options.addOption("''Hangar:''
  ''Attack Planes: '' (current max <<= App.SF.upgrades.currentUnitMax('AA')>>)", "AA", V.SF.Squad).showTextBox()>>
	<<run _options.addOption("  ''Transport Planes: '' (current max <<= App.SF.upgrades.currentUnitMax('TA')>>)", "TA", V.SF.Squad).showTextBox()>>
	<<if _T1>>
		<<run _options.addOption(" ''Spaceplane: '' (current max <<= App.SF.upgrades.currentUnitMax('SpacePlane')>>)", "SpacePlane", V.SF.Squad).showTextBox()>>
		<<run _options.addOption(" ''Gunship: '' (current max <<= App.SF.upgrades.currentUnitMax('GunS')>>)", "GunS", V.SF.Squad).showTextBox()>>
	<</if>>
<</if>>

<<if App.SF.unlocked.launchBay()>>
	<<run _options.addOption("''Launch Bay:''
 ''Satellite: '' (current max <<= App.SF.upgrades.currentUnitMax('Satellite')>>)", "Satellite", V.SF.Squad).showTextBox()>>
	<<if $terrain != "oceanic">>
		<<run _options.addOption(" ''Giant Robot: '' (current max <<= App.SF.upgrades.currentUnitMax('GiantRobot')>>)", "GiantRobot", V.SF.Squad).showTextBox()>>
	<</if>>
	<<run _options.addOption(" ''Cruise Missile: '' (current max <<= App.SF.upgrades.currentUnitMax('MissileSilo')>>)", "MissileSilo", V.SF.Squad).showTextBox()>>
<</if>>

<<if App.SF.unlocked.navalYard()>>
	<<run _options.addOption("

''Naval Yard:''
 ''Aircraft Carrier: '' (current max <<= App.SF.upgrades.currentUnitMax('AircraftCarrier')>>)", "AircraftCarrier", V.SF.Squad).showTextBox()>>
	<<run _options.addOption(" ''Submarine: '' (current max <<= App.SF.upgrades.currentUnitMax('Sub')>>)", "Sub", V.SF.Squad).showTextBox()>>
	<<run _options.addOption(" ''Amphibious Transport: '' (current max <<= App.SF.upgrades.currentUnitMax('HAT')>>)", "HAT", V.SF.Squad).showTextBox()>>
<</if>>

<<includeDOM _options.render()>>

<<if $SF.FS.Tension !== -1>>

The Colonel's current Tension: <<textbox "$SF.FS.Tension" $SF.FS.Tension "editSF">>
<</if>>


code:
App.Arcology.Cell.Apartment = class extends App.Arcology.Cell.BaseCell {
	/**
	 * @param {number} owner
	 * @param {number} type
	 */
	constructor(owner, type = 2) {
		super(owner);
		this.type = type;
	}

	static get cellName() {
		return "Apartments";
	}

	/**
	 * @returns {string}
	 */
	get colorClass() {
		switch (this.type) {
			case 1:
				return "luxuryApartments";
			case 2:
				return "apartments";
			case 3:
				return "denseApartments";
			default:
				return super.colorClass;
		}
	}

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		let message = "";
		switch (this.type) {
			case 1:
				message = "Luxury Apartments";
				break;
			case 2:
				message = "Apartments";
				break;
			case 3:
				message = "Dense Apartments";
				break;
		}
		return App.Arcology.getCellLink(path, message);
	}

	/**
	 * @returns {string|Node}
	 * @override @protected
	 */
	_setting() {
		let r = "";

		switch (this.type) {
			case 1:
				r = "improved for occupancy by the Free Cities' wealthiest citizens";
				break;
			case 2:
				r = "occupied by citizens of varying wealth and social standing";
				break;
			case 3:
				r = "upgraded for dense occupancy by as many citizens as possible";
				break;
		}

		if (this.owner === 1) {
			r = `This is a sector of the arcology's living areas, ${r}. You control this part of the arcology and all these tenants pay you rent.`;
		} else {
			r = `This is a privately-owned sector of the arcology's living areas, ${r}.`;
		}

		return r;
	}

	/**
	 * @returns {Node}
	 * @override @protected
	 */
	_body() {
		const fragment = document.createDocumentFragment();

		const cost = 10000 * V.upgradeMultiplierArcology;

		if (this.type !== 3) {
			fragment.append(this._makeUpgrade(
				"Upgrade this sector of apartments for dense occupancy by as many citizens as possible.",
				() => { this.type = 3; }, cost));
		}

		if (this.type !== 1) {
			fragment.append(this._makeUpgrade(
				"Improve this sector of apartments for occupancy by the Free Cities' wealthiest citizens.",
				() => { this.type = 1; }, cost));
		}

		if (this.type !== 2) {
			fragment.append(this._makeUpgrade(
				"Return this sector to standard, mixed housing.",
				() => { this.type = 2; }, cost));
		}

		return fragment;
	}

	/**
	 * @returns {boolean}
	 */
	canBeSold() {
		return true;
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	/** @returns {App.Arcology.Cell.Apartment} */
	clone() {
		return (new App.Arcology.Cell.Apartment(this.owner))._init(this);
	}

	get className() { return "App.Arcology.Cell.Apartment"; }
};


code:
/**
 * @param {Array<number>} path
 * @param {string} message
 * @returns {Node}
 */
App.Arcology.getCellLink = function(path, message) {
	return App.UI.DOM.passageLink(message, "Cell", () => { V.cellPath = path; });
};

/**
 * Upgrades all instances of cellClass and cellType to newType.
 * Intended for use on guaranteed single hits.
 *
 * @param {App.Arcology.Building} building
 * @param {typeof App.Arcology.Cell.BaseCell} cellClass
 * @param {*} cellType
 * @param {*} newType
 * @param {string} [key="type"]
 */
App.Arcology.cellUpgrade = function(building, cellClass, cellType, newType, key = "type") {
	building.findCells(cell => cell instanceof cellClass && cell[key] === cellType)
		.forEach(cell => { cell[key] = newType; });
};

/**
 * Updates V.arcologies[0].ownership.
 */
App.Arcology.updateOwnership = function() {
	const allCells = V.building.findCells(cell => !(cell instanceof App.Arcology.Cell.Filler));
	const ownedCells = allCells.filter(cell => cell.owner === 1);

	const ratio = ownedCells.length / allCells.length;

	V.arcologies[0].ownership = Math.round(100 * ratio);
};

/**
 * @param {string} [terrain="default"]
 * @returns {App.Arcology.Building}
 */
App.Arcology.defaultBuilding = function(terrain = "default") {
	/**
	 * @type {arcologyEnvironment}
	 */
	const env = {terrain: terrain, established: false, fs: ""};
	const candidates = App.Arcology.presets.filter(preset => preset.isAllowed(env));
	return candidates.pluck().construct(env).building;
};

/**
 * Order of the building sections. All possible sections have to be added here.
 *
 * @type {string[]}
 */
App.Arcology.sectionOrder = ["fountain", "penthouse", "spire", "shops", "ravine-markets", "apartments", "markets", "manufacturing"];

/**
 * @param {App.Entity.Facilities.Facility} facility
 * @param {string} [passageName]
 * @param {string} [statsStr]
 * @returns {Node}
 */
App.Arcology.facilityCellContent = function(facility, passageName, statsStr) {
	const res = document.createDocumentFragment();
	res.append(App.UI.DOM.passageLink(facility.UIName, passageName || facility.genericName));
	const report = facility.occupancyReport(false);
	if (report !== "") {
		const stats = document.createElement("span");
		stats.textContent = ` (${report})`;
		res.append(stats);
	}
	return res;
};

App.Arcology.Section = class extends App.Entity.Serializable {
	/**
	 * @param {string} id unique ID
	 * @param {Array<Array<App.Arcology.Cell.BaseCell>>} rows
	 * @param {boolean} [groundLevel=false] if the section the ground level, all lower layers are automatically in the
	 *     basement
	 */
	constructor(id, rows, groundLevel = false) {
		super();
		/**
		 * @type {string}
		 */
		this.id = id;
		/**
		 * @type {Array<Array<App.Arcology.Cell.BaseCell>>}
		 */
		this.rows = rows;
		this.groundLevel = groundLevel;
	}

	get width() {
		let maxWidth = 0;

		this.rows.forEach(cells => {
			let width = 0;
			cells.forEach(cell => {
				width += cell.width;
			});
			maxWidth = Math.max(maxWidth, width);
		});
		return maxWidth;
	}

	/**
	 * @param {number} elementWidth in %
	 * @param {number} index
	 * @returns {DocumentFragment}
	 */
	render(elementWidth, index) {
		/**
		 * @param {App.Arcology.Cell.BaseCell} cell
		 * @param {number} rowIndex
		 * @param {number} cellIndex
		 * @returns {HTMLDivElement}
		 */
		function createCell(cell, rowIndex, cellIndex) {
			return cell.renderCell([index, rowIndex, cellIndex], elementWidth);
		}

		/**
		 * @param {Array<App.Arcology.Cell.BaseCell>} row
		 * @param {number} rowIndex
		 * @returns {HTMLDivElement}
		 */
		function createRow(row, rowIndex) {
			const div = document.createElement("div");
			div.classList.add("row");

			row.forEach((cell, cellIndex) => {
				div.append(createCell(cell, rowIndex, cellIndex));
			});

			return div;
		}

		const fragment = document.createDocumentFragment();

		this.rows.forEach((row, rowIndex) => {
			fragment.append(createRow(row, rowIndex));
		});

		return fragment;
	}

	/**
	 * @param {Array<number>} path of the form [i, j]
	 * @param {App.Arcology.Building} containingBuilding
	 * @returns {Node}
	 */
	renderCell(path, containingBuilding) {
		return this.rows[path[0]][path[1]].cellPassage(containingBuilding);
	}

	/**
	 * @param {function(App.Arcology.Cell.BaseCell): boolean} predicate
	 * @returns {Array<App.Arcology.Cell.BaseCell>}
	 */
	findCells(predicate) {
		const cells = [];
		for (const row of this.rows) {
			for (const cell of row) {
				if (predicate(cell)) {
					cells.push(cell);
				}
			}
		}
		return cells;
	}

	/**
	 * Replaces the first occurrence of oldCell with newCell
	 *
	 * @param {App.Arcology.Cell.BaseCell} oldCell
	 * @param {App.Arcology.Cell.BaseCell} newCell
	 * @returns {boolean}
	 */
	replaceCell(oldCell, newCell) {
		for (const row of this.rows) {
			for (let i = 0; i < row.length; i++) {
				if (row[i] === oldCell) {
					row[i] = newCell;
					return true;
				}
			}
		}
		return false;
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	clone() {
		return (new App.Arcology.Section())._init(this);
	}

	get className() { return "App.Arcology.Section"; }
};

App.Arcology.Building = class extends App.Entity.Serializable {
	/**
	 * @param {string} layout reference to the used layout so we now how to do layout specific actions. (upgrading)
	 * @param {Array<App.Arcology.Section>} sections
	 */
	constructor(layout, sections) {
		super();
		/**
		 * @type {string}
		 */
		this.layout = layout;
		/**
		 * List of all already taken upgrades.
		 * @type {Array<string>}
		 */
		this.usedUpgrades = [];
		/**
		 * @type {Array<App.Arcology.Section>}
		 */
		this.sections = sections;
	}

	/**
	 * @returns {DocumentFragment}
	 */
	render() {
		const fragment = document.createDocumentFragment();

		let maxWidth = 0;
		this.sections.forEach(section => {
			maxWidth = Math.max(section.width, maxWidth);
		});
		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) => {
				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;
				}
			});

		fragment.append(upperLevels, basement);
		return fragment;
	}

	/**
	 * @param {Array<*>} path
	 * @returns {Node}
	 */
	renderCell(path) {
		return this.sections[path[0]].renderCell(path.slice(1), this);
	}

	/**
	 * @param {function(App.Arcology.Cell.BaseCell): boolean} predicate
	 * @returns {Array<App.Arcology.Cell.BaseCell>}
	 */
	findCells(predicate) {
		return this.sections.reduce(
			(cells, section) => {
				cells.push(...section.findCells(predicate));
				return cells;
			}, []);
	}

	/**
	 * @param {App.Arcology.Cell.BaseCell} oldCell
	 * @param {App.Arcology.Cell.BaseCell} newCell
	 * @returns {boolean}
	 */
	replaceCell(oldCell, newCell) {
		for (let section of this.sections) {
			if (section.replaceCell(oldCell, newCell)) {
				return true;
			}
		}
		return false;
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		if (config.layout === undefined) {
			config.layout = V.terrain;
		}
	}

	clone() {
		return (new App.Arcology.Building())._init(this);
	}

	get className() { return "App.Arcology.Building"; }
};


code:
:: Cell [nobr jump-from-safe no-history]

<<set $nextButton = "Back", $nextLink = "Main">>

<<includeDOM V.building.renderCell(V.cellPath)>>


code:
App.Arcology.Cell.Decorative = class extends App.Arcology.Cell.BaseCell {
	/**
	 * @param {object} params
	 * @param {number} [params.width] in cells
	 * @param {number} [params.xOffset=0] in %
	 * @param {number} [params.yOffset=0] in px
	 * @param {number} [params.rotation=0] in deg
	 * @param {number} [params.cellHeight=0] in px, if default height is not enough to stop stuff going offscreen
	 * @param {number} [params.absoluteWidth=0] 0/1, if width and xOffset should be read as absolute pixels
	 */
	constructor({width = 1, xOffset = 0, yOffset = 0, rotation = 0, cellHeight = 0, absoluteWidth = 0} = {}) {
		super(1);
		this._width = width;
		this._xOffset = xOffset;
		this._yOffset = yOffset;
		this._rotation = rotation;
		this._cellHeight = cellHeight;
		this._absoluteWidth = absoluteWidth;
	}

	get width() {
		return this._absoluteWidth ? 0 : this._width;
	}

	renderCell(path, width) {
		const outerCell = document.createElement("div");
		outerCell.style.width = `${width * this.width}%`;

		if (this._cellHeight > 0) {
			outerCell.style.height = `${this._cellHeight}px`;
		}

		const innerCell = document.createElement("div");
		innerCell.classList.add("decorative");
		if (this._absoluteWidth) {
			innerCell.style.width = `${this._width}px`;
		}
		innerCell.style.transform = `translate(${this._xOffset}${this._absoluteWidth ? "px" : "%"}, ${this._yOffset}px) rotate(${this._rotation}deg)`;
		outerCell.append(innerCell);

		return outerCell;
	}

	get className() { return "App.Arcology.Cell.Decorative"; }

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	clone() {
		return (new App.Arcology.Cell.Decorative())._init(this);
	}
};


code:
App.Arcology.Cell.Filler = class extends App.Arcology.Cell.BaseCell {
	constructor(width) {
		super(1);
		this._width = width;
	}

	get width() {
		return this._width;
	}

	renderCell(path, width) {
		const outerCell = document.createElement("div");
		outerCell.style.width = `${width * this.width}%`;
		return outerCell;
	}

	get className() { return "App.Arcology.Cell.Filler"; }

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	clone() {
		return (new App.Arcology.Cell.Filler())._init(this);
	}
};


code:
App.Arcology.Cell.Manufacturing = class extends App.Arcology.Cell.BaseCell {
	/**
	 * @param {number} owner
	 * @param {string} type
	 */
	constructor(owner, type = "Manufacturing") {
		super(owner);
		this.type = type;
	}

	static get cellName() {
		return "Manufacturing";
	}

	/**
	 * @returns {string}
	 */
	get colorClass() {
		switch (this.type) {
			case "Manufacturing":
				return "manufacturing";
			case "Dairy":
				return "dairy";
			case "Farmyard":
				return "farmyard";
			case "Barracks":
				return "barracks";
			case "Weapon Manufacturing":
				return "weaponsManufacturing";
			case "Pens":
				return "pens";
			case "Sweatshops":
				return "sweatshops";
			default:
				return super.colorClass;
		}
	}

	/**
	 * @returns {boolean}
	 */
	isBaseType() {
		return this.type === "Manufacturing";
	}

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		if (this.type === "Dairy") {
			return App.Arcology.facilityCellContent(App.Entity.facilities.dairy);
		}
		if (this.type === "Farmyard") {
			return App.Arcology.facilityCellContent(App.Entity.facilities.farmyard);
		}
		switch (this.type) {
			case "Manufacturing":
			case "Pens":
			case "Sweatshops":
				return App.Arcology.getCellLink(path, this.type);
			case "Barracks":
				return App.UI.DOM.passageLink("Barracks", "Barracks");
			case "Weapon Manufacturing":
				return App.UI.DOM.passageLink("Weapons Manufacturing", "weaponsManufacturing");
			default:
				return App.UI.DOM.makeElement("span", `ERROR: invalid type: ${this.type}`, "error");
		}
	}

	/**
	 * @returns {string|Node}
	 * @protected @override
	 */
	_setting() {
		let r = "";

		switch (this.type) {
			case "Manufacturing":
				r = "rented to a variety of tenants for manufacturing purposes";
				if (this.owner === 1) {
					r += ". You control this part of the arcology and all these tenants pay you rent";
				}
				break;
			case "Sweatshops":
				if (this.owner === 1) {
					r = "designed for labor intensive manufacturing by menial slaves";
				} else {
					r = "rented to a variety of tenants for manufacturing purposes";
				}
				break;
			case "Pens":
				r = "designed to house hundreds of slaves for paying owners";
				if (this.owner === 1) {
					r += ". You control this part of the arcology. If you own menial slaves, they will be kept here; otherwise, unused space will be rented to other slave brokers";
				}
				break;
		}

		if (this.owner === 1) {
			return `This is a space in the arcology's service areas, ${r}.`;
		}
		return `This is a privately-owned space in the arcology's service areas, ${r}.`;
	}

	/**
	 * @returns {Node}
	 * @protected @override
	 */
	_body() {
		const fragment = document.createDocumentFragment();

		const pensDOM = pens(this);
		if (pensDOM !== null) {
			console.log("if");
			fragment.append(pensDOM);

			const p = document.createElement("p");
			p.append(upgrades(this));
			console.log("up");
			fragment.append(p);
		} else {
			console.log("bor");
			fragment.append(upgrades(this));
		}

		return fragment;

		/**
		 * @param {App.Arcology.Cell.Manufacturing} thisCell this is apparently undefined inside???
		 * @returns {null|HTMLParagraphElement}
		 */
		function pens(thisCell) {
			if (thisCell.type !== "Pens") {
				return null;
			}

			const paragraph = document.createElement("p");

			const popCap = menialPopCap();
			paragraph.append(App.UI.DOM.makeElement("div", popCap.text),
				App.UI.DOM.makeElement("div", `In total you are able to personally house a total of ${num(popCap.value)} menial slaves.`));

			if (V.menials + V.menialBioreactors + V.fuckdolls > 0) {
				let r = "You own ";
				let list = [];
				if (V.menials > 0) {
					list.push(numberWithPluralOne(V.menials, "menial slave"));
				}
				if (V.menialBioreactors > 0) {
					list.push(numberWithPluralOne(V.menialBioreactors, "standard bioreactor"));
				}
				if (V.fuckdolls > 0) {
					list.push(numberWithPluralOne(V.fuckdolls, "standard Fuckdoll"));
				}

				r += `${list.toStringExt()}, `;

				if (V.menials + V.menialBioreactors + V.fuckdolls > 500) {
					r += "partially ";
				}

				r += "housed in this sector.";

				if (V.menials > 0 && V.Sweatshops > 0) {
					r += ` The simple labor slaves toil in ${V.arcologies[0].name}'s sweatshops, and only return here to sleep.`;
				}
				if (V.fuckdolls > 0 && V.arcade > 0) {
					r += ` The menial Fuckdolls are endlessly cycled through ${V.arcadeName}. They're restrained there and used by the public until their holes are no longer appealing, and then cycled back down here to rest until they've tightened up again.`;
				}
				if (V.menialBioreactors && V.dairyUpgradeMenials) {
					r += ` Whenever there's space in ${V.dairyName}, menial Bioreactors are taken out of storage here and restrained there, with ${V.dairyName}'s powerful hookups draining them of their useful fluids and feeding them generously so they can produce more.`;
				}

				paragraph.append(r);
			}

			return paragraph;
		}

		/**
		 * @param {App.Arcology.Cell.Manufacturing} thisCell
		 * @returns {DocumentFragment}
		 */
		function upgrades(thisCell) {
			const fragment = document.createDocumentFragment();
			const cost = Math.trunc(10000 * V.upgradeMultiplierArcology);

			if (V.dairy === 0) {
				fragment.append(thisCell._makeUpgrade(
					"Construct a dairy to milk slaves on an industrial scale",
					() => {
						V.dairy = 5;
						thisCell.type = "Dairy";
					}, cost, "and will incur upkeep costs"
				));
			}

			if (V.experimental.food === 1) {
				if (V.farmyard === 0) {
					fragment.append(thisCell._makeUpgrade(
						"Construct a farming facility to grow food for your arcology and house animals",
						() => {
							V.farmyard = 5;
							thisCell.type = "Farmyard";
						}, cost, "and will incur upkeep costs"
					));
				}
			}

			if (V.mercenaries) {
				if (V.barracks !== 1) {
					fragment.append(thisCell._makeUpgrade(
						"Build an armory to properly house your mercenaries",
						() => {
							V.barracks = 1;
							thisCell.type = "Barracks";
						}, cost, "but will reduce mercenary upkeep"
					));
				}
			}

			if (V.secExpEnabled > 0 && !V.SecExp.buildings.weapManu) {
				fragment.append(thisCell._makeUpgrade(
					"Convert this sector to weapons manufacturing",
					() => {
						App.SecExp.weapManu.Init();
						thisCell.type = "Weapon Manufacturing";
					}, cost, "but will provide a weekly income and will unlock upgrades for our troops"
				));
			}

			if (thisCell.type !== "Pens") {
				fragment.append(thisCell._makeUpgrade(
					"Convert to pens to increase the number of menial slaves you can house",
					() => {
						thisCell.type = "Pens";
					}, cost
				));
			}

			if (thisCell.type !== "Sweatshops") {
				fragment.append(thisCell._makeUpgrade(
					"Convert these facilities to use the labor of menial slaves",
					() => {
						thisCell.type = "Sweatshops";
					}, cost
				));
			}

			if (thisCell.type !== "Manufacturing") {
				fragment.append(thisCell._makeUpgrade(
					"Return this sector to standard manufacturing",
					() => {
						thisCell.type = "Manufacturing";
					}, cost
				));
			}

			return fragment;
		}
	}

	/**
	 * @returns {boolean}
	 */
	canBeSold() {
		return ["Manufacturing", "Sweatshops", "Pens"].includes(this.type);
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	/** @returns {App.Arcology.Cell.Manufacturing} */
	clone() {
		return (new App.Arcology.Cell.Manufacturing(this.owner))._init(this);
	}

	get className() {
		return "App.Arcology.Cell.Manufacturing";
	}
};


code:
App.Arcology.Cell.Market = class extends App.Arcology.Cell.BaseCell {
	/**
	 * @param {number} owner
	 * @param {string} type
	 */
	constructor(owner, type = "Markets") {
		super(owner);
		this.type = type;
	}

	static get cellName() {
		return "Markets";
	}

	/**
	 * @returns {string}
	 */
	get colorClass() {
		switch (this.type) {
			case "Markets":
				return "markets";
			case "Arcade":
				return "arcade";
			case "Pit":
				return "pit";
			case "Transport Hub":
				return "transportHub";
			case "Corporate Market":
				return "corporateMarket";
			default:
				return super.colorClass;
		}
	}

	isBaseType() {
		return this.type === "Markets";
	}

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		switch (this.type) {
			case "Arcade":
				return App.Arcology.facilityCellContent(App.Entity.facilities.arcade);
			case "Pit":
				return App.Arcology.facilityCellContent(App.Entity.facilities.pit);
			case "Markets":
				return App.Arcology.getCellLink(path, "Markets");
			case "Transport Hub":
				return App.UI.DOM.passageLink("Transport Hub", "transportHub");
			case "Corporate Market":
				return App.UI.DOM.passageLink(
					"Corporate Market",
					"Market",
					() => {
						V.market = new App.Markets.GlobalVariable();
						V.market.slaveMarket = "corporate";
						V.market.newSlaves = [];
						V.market.numArcology = 1;
						V.nextButton = "Back to Main";
						V.nextLink = "Main";
						V.returnTo = "Main";
					}
				);
			default:
				return App.UI.DOM.makeElement("span", "ERROR: invalid type: " + this.type, "error");
		}
	}

	/**
	 * @returns {string|Node}
	 * @protected @override
	 */
	_setting() {
		/* no need to check type, since you can only get here with the basic type */
		let r = "area of the concourse occupied by large stores and markets, many of which sell slaves";

		if (this.owner === 1) {
			return `This is an ${r}. You control this part of the arcology and all these tenants pay you rent.`;
		}
		return `This is a privately-owned ${r}.`;
	}

	/**
	 * @returns {Node}
	 * @protected @override
	 */
	_body() {
		const fragment = document.createDocumentFragment();

		const cost = Math.trunc(10000 * V.upgradeMultiplierArcology);
		if (V.arcade === 0) {
			fragment.append(this._makeUpgrade(
				"Construct a sex arcade to present slaves' holes for public use",
				() => {
					this.type = "Arcade";
					V.arcade = 10;
				}, cost, "and will incur upkeep costs"
			));
		}

		if (!V.pit) {
			fragment.append(this._makeUpgrade(
				"Build a pit to host proper slave fights",
				() => {
					this.type = "Pit";
					App.Facilities.Pit.init();
				}, cost
			));
		}

		if (V.secExpEnabled > 0 && !V.SecExp.buildings.transportHub) {
			fragment.append(this._makeUpgrade(
				"Centralize and modernize the transport hub",
				() => {
					this.type = "Transport Hub";
					App.SecExp.transportHub.Init();
				}, cost
			));
		}

		const corpCost = Math.trunc(10000 * V.upgradeMultiplierArcology);
		if (V.corp.Market === 0 && V.corp.Incorporated === 1) {
			fragment.append(this._makeUpgrade(
				"Create a flagship slave market for your corporation here",
				() => {
					this.type = "Corporate Market";
					V.corp.Market = 1;
					V.corp.Cash -= corpCost;
				}, 0, ` Costs ${cashFormat(corpCost)} of the corporation's money`
			));
		}

		return fragment;
	}

	/**
	 * @returns {boolean}
	 */
	canBeSold() {
		return this.type === "Markets";
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	/** @returns {App.Arcology.Cell.Market} */
	clone() {
		return (new App.Arcology.Cell.Market(this.owner))._init(this);
	}

	get className() { return "App.Arcology.Cell.Market"; }
};


code:
App.Arcology.Cell.Penthouse = class extends App.Arcology.Cell.BaseCell {
	constructor() {
		super(1);
	}

	/**
	 * @returns {string}
	 */
	get colorClass() {
		return "penthouse";
	}

	/**
	 * @returns {number}
	 */
	get width() {
		return 2;
	}

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		const fragment = document.createDocumentFragment();

		const link = App.UI.DOM.passageLink("Penthouse", "Manage Penthouse");
		const hotkey = App.UI.DOM.makeElement("span", App.UI.Hotkeys.hotkeys("Manage Penthouse"), "hotkey");
		if (V.verticalizeArcologyLinks === 0) {
			const div = document.createElement("div");
			div.append(link, " ", hotkey);
			fragment.append(div);
		} else {
			fragment.append(link, " ", hotkey);
		}

		const wrapper = getWrapper(fragment);
		const fcs = App.Entity.facilities;

		/**
		 * @param {App.Entity.Facilities.Facility} facility
		 * @param {string} [passageName]
		 */
		function addFacility(facility, passageName) {
			if (facility.established) {
				const report = facility.occupancyReport(false);
				wrapper.append(createFacilityDiv(
					App.UI.DOM.passageLink(facility.UIName, passageName || facility.genericName),
					report ? `(${report})` : null
				));
			}
		}

		addFacility(fcs.masterSuite);
		addFacility(fcs.headGirlSuite, "Head Girl Suite");
		addFacility(fcs.armory, "BG Select");
		addFacility(fcs.servantsQuarters);
		addFacility(fcs.spa);
		addFacility(fcs.nursery);
		addFacility(fcs.clinic);
		addFacility(fcs.schoolroom);
		addFacility(fcs.cellblock);

		if (V.incubator) {
			const inc = App.Entity.facilities.incubator;
			const link = App.UI.DOM.passageLink(inc.UIName, "Incubator");
			const desc = `(${numberWithPluralOne(inc.capacity - V.tanks.length, "empty tank")})`;

			if (V.readySlaves > 0) {
				wrapper.append(createFacilityDiv(link, desc, App.UI.DOM.makeElement("span", "[!]", "noteworthy")));
			} else {
				wrapper.append(createFacilityDiv(link, desc));
			}
		}

		if (V.researchLab.level > 0) {
			wrapper.append(createFacilityDiv(App.UI.DOM.passageLink("Prosthetic Lab", "Prosthetic Lab")));
		}

		return fragment;

		/**
		 * @param {ParentNode} outer
		 * @returns {HTMLDivElement}
		 */
		function getWrapper(outer) {
			const wrapper = document.createElement("div");
			if (V.verticalizeArcologyLinks !== 0) {
				let gridClass = `grid${V.verticalizeArcologyLinks}`;
				wrapper.classList.add("gridWrapper", gridClass);
			}
			outer.append(wrapper);
			return wrapper;
		}

		/**
		 *
		 * @param {HTMLElement} link
		 * @param {(Node|string)} [content]
		 * @returns {HTMLDivElement}
		 */
		function createFacilityDiv(link, content) {
			const div = document.createElement("div");
			div.append(link);
			// in collapsed mode additional information needs to be in it's own div to stop linebreaks at weird places
			if (V.verticalizeArcologyLinks === 0) {
				div.classList.add("collapsed");
				if (content) {
					div.append(" ", content);
				}
			} else if (content) {
				const innerDiv = document.createElement("div");
				innerDiv.append(content);
				div.append(" ", innerDiv);
			}
			return div;
		}
	}

	static _cleanupConfigScheme(config) {
		super._cleanupConfigScheme(config);
		// BC code
	}

	/** @returns {App.Arcology.Cell.Penthouse} */
	clone() {
		return new App.Arcology.Cell.Penthouse()._init(this);
	}

	get className() { return "App.Arcology.Cell.Penthouse"; }
};


code:
/**
 * @typedef {object} arcologyEnvironment
 * @property {string} terrain
 * @property {boolean} established
 * @property {string} fs
 */
/**
 * @typedef {object} buildingPreset
 * @property {function(arcologyEnvironment):boolean} isAllowed
 * @property {function(arcologyEnvironment):{building: App.Arcology.Building, apply: function():void}} construct
 */

/**
 * @type {Array<buildingPreset>}
 */
App.Arcology.presets = (function() {
	/**
	 * @typedef {object} sectionTemplate
	 * @property {string} id
	 * @property {Array<string>} rows
	 * @property {boolean} [ground]
	 */
	/**
	 * @typedef {Array<sectionTemplate|string>} buildingTemplate first entry is template name
	 */

	/*
	 NOTE: test new templates, broken templates WILL explode
	 t is markets; () is possible values for a sector, first is default;
	 [number] is for filler space, must be parsable by Number(), 1 equals the width of a normal cell
	 */
	const templates = {
		default: ["default",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["sss"]},
			{id: "apartments", rows: ["aaaa", "aaaa", "aaaa"]},
			{id: "markets", rows: ["ttttt"], ground: true},
			{id: "manufacturing", rows: ["mmmmm"]}],
		urban: ["urban",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["sss"]},
			{id: "apartments", rows: ["aaaa", "aaaa", "dddd"]},
			{id: "markets", rows: ["(dt)tt(dt)", "t(tm)(tm)t"], ground: true},
			{id: "manufacturing", rows: ["mmmm"]}],
		rural: ["rural",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["sss"]},
			{id: "apartments", rows: ["aaaaa", "aaaaa"]},
			{id: "markets", rows: ["tt(mt)(mt)tt"], ground: true},
			{id: "manufacturing", rows: ["mmmmm"]}],
		ravine: ["ravine",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["sss"]},
			{id: "ravine-markets", rows: ["ttttt"], ground: true},
			{id: "apartments", rows: ["aaaa", "aaaa", "aaaa"]},
			{id: "manufacturing", rows: ["mmmmm"]}],
		marine: ["marine",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["ssss"]},
			{id: "apartments", rows: ["laal", "aaaa", "aaaa"]},
			{id: "markets", rows: ["tt(mt)tt"], ground: true},
			{id: "manufacturing", rows: ["(tm)mmm(tm)"]}],
		oceanic: ["oceanic",
			{id: "penthouse", rows: ["p"]},
			{id: "shops", rows: ["sss"]},
			{id: "apartments", rows: ["llll", "aaaa", "aaaa"]},
			{id: "markets", rows: ["ttttt"], ground: true},
			{id: "manufacturing", rows: ["mmmmm"]}],
		dick: ["dick", // yes, this is a giant dick
			{id: "penthouse", rows: ["l", "p"]},
			{id: "apartments", rows: ["a", "a", "a", "d[0.75]a[0.75]d", "dd[0.25]s[0.25]dd"]},
			{id: "markets", rows: ["ttsstt"], ground: true},
			{id: "manufacturing", rows: ["tm[0.25]m[0.25]mt", "m[0.75]m[0.75]m"]}],
	};

	/**
	 * @param {sectionTemplate[]} template
	 * @returns {App.Arcology.Building}
	 */
	function templateToBuilding(template) {
		const sections = [];
		const layout = template[0];
		for (let i = 1; i < template.length; i++) {
			sections.push(getSection(template[i]));
		}
		return new App.Arcology.Building(layout, sections);

		/**
		 * @param {sectionTemplate} section
		 * @returns {App.Arcology.Section}
		 */
		function getSection(section) {
			const rows = [];
			for (const row of section.rows) {
				rows.push(getRow(row));
			}
			return new App.Arcology.Section(section.id, rows, section.ground === true /* to ensure no undefined gets through */);
		}

		/**
		 * @param {string} rowTemplate
		 * @returns {App.Arcology.Cell.BaseCell[]}
		 */
		function getRow(rowTemplate) {
			const cells = [];
			const iter = rowTemplate[Symbol.iterator]();

			let next = iter.next();
			while (!next.done) {
				if (next.value === "(") {
					next = iter.next();
					const cell = charToCell(next.value).cell;
					do {
						cell.allowedConversions.push(charToCell(next.value).code);
						next = iter.next();
					} while (next.value !== ")");
					cells.push(cell);
				} else if (next.value === "[") {
					let number = "";
					next = iter.next();
					while (next.value !== "]") {
						number += next.value;
						next = iter.next();
					}
					cells.push(new App.Arcology.Cell.Filler(Number(number)));
				} else {
					cells.push(charToCell(next.value).cell);
				}
				next = iter.next();
			}

			return cells;
		}

		/**
		 * @param {string} char
		 * @returns {{cell: App.Arcology.Cell.BaseCell, code:string}}
		 */
		function charToCell(char) {
			switch (char) {
				case "p":
					return {cell: new App.Arcology.Cell.Penthouse(), code: "Penthouse"};
				case "s":
					return {cell: new App.Arcology.Cell.Shop(1), code: "Shop"};
				case "l":
					return {cell: new App.Arcology.Cell.Apartment(1, 1), code: "Apartment"};
				case "a":
					return {cell: new App.Arcology.Cell.Apartment(1), code: "Apartment"};
				case "d":
					return {cell: new App.Arcology.Cell.Apartment(1, 3), code: "Apartment"};
				case "t":
					return {cell: new App.Arcology.Cell.Market(1), code: "Market"};
				case "m":
					return {cell: new App.Arcology.Cell.Manufacturing(1), code: "Manufacturing"};
				default:
					return {cell: new App.Arcology.Cell.BaseCell(1), code: "BaseCell"};
			}
		}
	}

	/**
	 * @param {App.Arcology.Building} building
	 * @param {arcologyEnvironment} environment
	 * @returns {{building: App.Arcology.Building, apply: function()}}
	 */
	function randomizeBuilding(building, environment) {
		const apply = [];
		if (Math.random() < 0.5) {
			apply.push(addFsShop(building, environment.fs));
		}
		return {building: building, apply: () => { apply.forEach(a => { a(); }); }};
	}

	/**
	 * @param {App.Arcology.Building} building
	 * @param {string} fs
	 * @returns {function():void}
	 */
	function addFsShop(building, fs) {
		function randomShop() {
			return /** @type {App.Arcology.Cell.Shop} */(building.findCells(cell => cell instanceof App.Arcology.Cell.Shop).random());
		}

		switch (fs) {
			case "Supremacist":
				randomShop().type = "Supremacist";
				return () => { V.FSPromenade.Supremacist = 1; };
			case "Subjugationist":
				randomShop().type = "Subjugationist";
				return () => { V.FSPromenade.Subjugationist = 1; };
			case "GenderRadicalist":
				randomShop().type = "Gender Radicalist";
				return () => { V.FSPromenade.GenderRadicalist = 1; };
			case "GenderFundamentalist":
				randomShop().type = "Gender Fundamentalist";
				return () => { V.FSPromenade.GenderFundamentalist = 1; };
			case "Paternalist":
				randomShop().type = "Paternalist";
				return () => { V.FSPromenade.Paternalist = 1; };
			case "Degradationist":
				randomShop().type = "Degradationist";
				return () => { V.FSPromenade.Degradationist = 1; };
			case "AssetExpansionist":
				randomShop().type = "Asset Expansionist";
				return () => { V.FSPromenade.AssetExpansionist = 1; };
			case "SlimnessEnthusiast":
				randomShop().type = "Slimness Enthusiast";
				return () => { V.FSPromenade.SlimnessEnthusiast = 1; };
			case "TransformationFetishist":
				randomShop().type = "Transformation Fetishist";
				return () => { V.FSPromenade.TransformationFetishist = 1; };
			case "BodyPurist":
				randomShop().type = "Body Purist";
				return () => { V.FSPromenade.BodyPurist = 1; };
			case "MaturityPreferentialist":
				randomShop().type = "Maturity Preferentialist";
				return () => { V.FSPromenade.MaturityPreferentialist = 1; };
			case "YouthPreferentialist":
				randomShop().type = "Youth Preferentialist";
				return () => { V.FSPromenade.YouthPreferentialist = 1; };
			case "Pastoralist":
				randomShop().type = "Pastoralist";
				return () => { V.FSPromenade.Pastoralist = 1; };
			case "PhysicalIdealist":
				randomShop().type = "Physical Idealist";
				return () => { V.FSPromenade.PhysicalIdealist = 1; };
			case "ChattelReligionist":
				randomShop().type = "Chattel Religionist";
				return () => { V.FSPromenade.ChattelReligionist = 1; };
			case "RomanRevivalist":
				randomShop().type = "Roman Revivalist";
				return () => { V.FSPromenade.RomanRevivalist = 1; };
			case "NeoImperialist":
				randomShop().type = "Neo-Imperialist";
				return () => { V.FSPromenade.NeoImperialist = 1; };
			case "AztecRevivalist":
				randomShop().type = "Aztec Revivalist";
				return () => { V.FSPromenade.AztecRevivalist = 1; };
			case "EgyptianRevivalist":
				randomShop().type = "Egyptian Revivalist";
				return () => { V.FSPromenade.EgyptianRevivalist = 1; };
			case "EdoRevivalist":
				randomShop().type = "Edo Revivalist";
				return () => { V.FSPromenade.EdoRevivalist = 1; };
			case "ArabianRevivalist":
				randomShop().type = "Arabian Revivalist";
				return () => { V.FSPromenade.ArabianRevivalist = 1; };
			case "ChineseRevivalist":
				randomShop().type = "Chinese Revivalist";
				return () => { V.FSPromenade.Degradationist = 1; };
			case "Repopulationist":
				randomShop().type = "Repopulationist";
				return () => { V.FSPromenade.Repopulationist = 1; };
			case "Eugenics":
				randomShop().type = "Eugenics";
				return () => { V.FSPromenade.Eugenics = 1; };
			case "HedonisticDecadence":
				randomShop().type = "Hedonism";
				return () => { V.FSPromenade.Hedonism = 1; };
			case "IntellectualDependency":
				randomShop().type = "Intellectual Dependency";
				return () => { V.FSPromenade.IntellectualDependency = 1; };
			case "SlaveProfessionalism":
				randomShop().type = "Slave Professionalism";
				return () => { V.FSPromenade.SlaveProfessionalism = 1; };
			case "PetiteAdmiration":
				randomShop().type = "Petite Admiration";
				return () => { V.FSPromenade.PetiteAdmiration = 1; };
			case "StatuesqueGlorification":
				randomShop().type = "Statuesque Glorification";
				return () => { V.FSPromenade.StatuesqueGlorification = 1; };
			default:
				return () => {};
		}
	}

	return [
		/* basic types for controlled start */
		{
			isAllowed: env => !env.established && env.terrain === "default",
			construct: () => { return {building: templateToBuilding(templates.default), apply: () => {}}; }
		}, {
			isAllowed: env => !env.established && env.terrain === "urban",
			construct: () => { return {building: templateToBuilding(templates.urban), apply: () => {}}; }
		}, {
			isAllowed: env => !env.established && env.terrain === "rural",
			construct: () => { return {building: templateToBuilding(templates.rural), apply: () => {}}; }
		}, {
			isAllowed: env => !env.established && env.terrain === "ravine",
			construct: () => { return {building: templateToBuilding(templates.ravine), apply: () => {}}; }
		}, {
			isAllowed: env => !env.established && env.terrain === "marine",
			construct: () => { return {building: templateToBuilding(templates.marine), apply: () => {}}; }
		}, {
			isAllowed: env => !env.established && env.terrain === "oceanic",
			construct: () => { return {building: templateToBuilding(templates.oceanic), apply: () => {}}; }
		},
		/* crazy presets for established arcologies TODO */
		{
			isAllowed: env => env.established && env.terrain === "default",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.default), env); }
		}, {
			isAllowed: env => env.established && env.terrain === "urban",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.urban), env); }
		}, {
			isAllowed: env => env.established && env.terrain === "rural",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.rural), env); }
		}, {
			isAllowed: env => env.established && env.terrain === "ravine",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.ravine), env); }
		}, {
			isAllowed: env => env.established && env.terrain === "marine",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.marine), env); }
		}, {
			isAllowed: env => env.established && env.terrain === "oceanic",
			construct: env => { return randomizeBuilding(templateToBuilding(templates.oceanic), env); }
		}, {
			isAllowed: env => env.established && Math.random() < 0.1,
			construct: env => { return randomizeBuilding(templateToBuilding(templates.dick), env); }
		},
	];
}());

/**
 * @param {arcologyEnvironment} environment
 * @returns {buildingPreset}
 */
App.Arcology.randomPreset = function(environment) {
	return App.Arcology.presets.filter(p => p.isAllowed(environment)).random();
};

/**
 * Shows all possible upgrades for a given building.
 * @param {App.Arcology.Building} building
 * @returns {HTMLElement}
 */
App.Arcology.upgrades = function(building) {
	const outerDiv = document.createElement("div");

	/**
	 * @typedef upgrade
	 * @property {string} id used to identify already build upgrades, unique!
	 * @property {Array<string>} layouts
	 * @property {Array<string>} exclusive any upgrade is always exclusive to itself. NOTE: keep in mind that
	 *     exclusiveness has to be added to both upgrades!
	 * @property {string} name as shown to player.
	 * @property {string} desc Fits in a sentence like this: The next major upgrade needed is "desc"
	 * @property {number} cost
	 * @property {function():void} apply
	 */
	/** @type {Array<upgrade>} */
	const upgrades = [
		{
			id: "spire",
			layouts: ["default", "urban", "rural", "ravine", "marine", "oceanic"],
			exclusive: [], name: "spire",
			desc: "the addition of a spire at the top of the arcology to increase the space available for the wealthiest citizens to own whole floors",
			cost: 250000, apply: () => {
				building.sections.push(new App.Arcology.Section("spire", [
					[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)]
				]));
				V.spire = 1;
			}
		}, {
			id: "fountain",
			layouts: ["dick"],
			exclusive: [], name: "fountain",
			desc: "a monumental fountain on top of the arcology using the latest advancements in building technology making your arcology known far and wide as a great supporter of modern architecture",
			cost: 250000, apply: () => {
				V.building.sections.push(new App.Arcology.Section("fountain", [[
					new App.Arcology.Cell.Decorative({
						width: 170, rotation: 70, xOffset:-130, yOffset: 220, absoluteWidth:1, cellHeight: 330
					}),
					new App.Arcology.Cell.Decorative({
						width: 250, rotation: 95, xOffset:-110, yOffset: 80, absoluteWidth:1
					}),
					new App.Arcology.Cell.Decorative({
						width: 190, rotation: 115, xOffset:-30, yOffset: 190, absoluteWidth:1
					}),
				]]));
				V.spire = 1;
			}
		}
	];

	let count = 0;
	for (let upgrade of upgrades) {
		if (upgrade.layouts.includes(building.layout)
			&& !building.usedUpgrades.includesAny(upgrade.id, ...upgrade.exclusive)) {
			const div = document.createElement("div");
			div.classList.add("choices");
			const cost = upgrade.cost * V.upgradeMultiplierArcology;
			div.append(`...${upgrade.desc}. `, App.UI.DOM.makeElement("span", `This huge project will cost ${cashFormat(cost)} `, "note"),
				App.UI.DOM.passageLink(`Build ${upgrade.name}`, passage(), () => {
					if (building.usedUpgrades.length === 0) {
						// the first major upgrade gives skill, successive ones not, mainly because there might be a
						// different number depending on layout.
						V.PC.skill.engineering++;
					}
					building.usedUpgrades.push(upgrade.id);
					upgrade.apply();
					cashX(-cost, "capEx");
				}));
			outerDiv.append(div);
			count++;
		}
	}

	if (count === 0) {
		return App.UI.DOM.makeElement("span", "The arcology structure is fully upgraded.", "note");
	} else {
		if (count === 1) {
			outerDiv.prepend("The next major upgrade is...");
		} else {
			outerDiv.prepend("Possible major upgrades to the arcology are ...");
		}
		return outerDiv;
	}
};