code:
App.Mods.SF.UnitText = function(input) {
	let text = ``;
	const S = V.SF.Squad;
	// Sorted by case
	let appear = `is currently constructed in a haphazard fashion.`;
	let barracks = `Soldiers' cots are mixed in with weapons crates and ammunition.`;
	let slave = `Cages for processing slaves lie off to one side,`;
	let common = `and in the center is a common area with tables for soldiers to gather around for meals or rowdy conversations.`;
	let garage = ``;
	let drone = ``;
	let hangar = ``;
	let launch = ``;
	let artillery = ``;
	let comms = ``;
	let training = ``;

	const Quantity = `the ${num(V.SF.ArmySize)} members of ${V.SF.Lower}`;

	let weapons = `The weapons are mostly worn rifles that have already seen years of service before ${V.SF.Lower} acquired them.`;
	let armor1 = `The body armor is enough to stop smaller calibers, but nothing serious.`;
	let radio = ``;
	let helmets = ``;
	let ammo0 = ``;
	let uniforms = ``;
	let special = ``;
	let exo = ``;

	let amphet = ``;
	let phen = ``;
	let steroid = ``;
	let downer = ``;
	let concen = ``;
	let stimpack = ``;
	let stabilizer = ``;

	let a = `have been recommissioned for use by ${V.SF.Lower}`;
	let b = `.`;
	let c = ``;
	let d = ``;
	let e = ``;
	let f = ``;
	let g = ``;
	let h = ``;
	let i = ``;
	let j = ``;
	let k = ``;

	let activate = `has been recommissioned for use by ${V.SF.Lower}. They`;
	let mechanics = `, and mechanics are methodically checking the recent purchases for battle-readiness`;
	let MG = `120 mm main gun is enough to handle the majority of opponents around the Free Cities.`;
	let engine1 = ``;
	let armor2 = ``;
	let armor22 = ``;
	let ammo1 = ``;
	let mg = ``;
	let fireC0 = ``;
	let fireC1 = ``;
	let fireC2 = ``;
	let fireC3 = ``;
	let turret = ``;

	let B = `has been recommissioned for use by ${V.SF.Lower}. They`;
	let C = `, mechanics are giving the new purchases a final tune-up`;
	let squad = `a squad`;
	let G1 = `20`;
	let G2 = `in a firefight`;
	let e0 = `The engine has been`;
	let engine3 = ``;
	let armor3 = ``;
	let tires = ``;
	let m1 = ``;
	let m2 = ``;
	let pod1 = ``;
	let pod2 = ``;

	let b1 = `has been sold to ${V.SF.Lower} through back channels to support a failing old world nation. The tank is so large it cannot fit inside the garage, and has`;
	let c1 = ``;
	let engines4 = `. Two engines power the left and right sides of the tank separately, leaving it underpowered and slow`;
	let gun0 = ``;
	let gun1 = ``;
	let gun2 = `an undersized main gun and makeshift firing system from a standard battle tank`;
	let armor5 = ``;
	let armor6 = ``;
	let cannon = ``;
	let laser = ``;
	let PGTframe = ``;

	let W1 = `only armed`;
	let W2 = `;`;
	let W3 = `a poor weapon against flying targets, but enough to handle ground forces`;
	let group = `A small group of attack VTOL have been recommissioned for use by ${V.SF.Lower}, enough to make up a squadron`;
	let engines = ``;
	let TAI = ``;
	let lock = ``;
	let support = ``;
	let stealth = ``;
	let scramble = ``;
	let PAI = ``;

	let Num = `number`;
	let type = `tiltrotor`;
	let capacity = `small platoon or 15`;
	let engines0 = ``;
	let engines01 = ``;
	let Radar = ``;
	let Armor = ``;
	let landing = ``;
	let miniguns = ``;
	let counter = ``;

	let engine20 = `ramjet engines in the atmosphere that can reach Mach 10`;
	let b5 = `has been purchased from an insolvent old world nation. It `;
	let shield = ``;
	let camera = ``;
	let efficiency = ``;
	let camera2 = ``;
	let drag = ``;
	let crew = ``;
	let engine2 = ``;
	let skin = ``;

	let activate2 = `has been recommissioned for use by ${V.SF.Lower}. Currently, it `;
	let barrels = `Miniguns and Gatling cannons line`;
	let distance = `, though the distance to ground targets renders the smaller calibers somewhat less useful`;
	let b4 = ``;
	let c2 = ``;
	let fuel = ``;
	let gsSpeed = ``;
	let countermeasures = ``;
	let ammunition = ``;
	let DFA = ``;
	let autocannon = ``;

	let loc1 = `An unused science satellite has been purchased from an old world nation. While currently useless, it holds potential to be a powerful tool.`;
	let gyro = ``;
	let telemetry = ``;
	let thrusters = ``;
	let solar = ``;
	let surviv = ``;
	let laser1 = ``;
	let heat = ``;
	let reactor = ``;
	let lens = ``;
	let kin = ``;

	let loc = `has been purchased from a crumbling old world nation. It`;
	let power = `Large batteries mounted in oversized shoulders power the robot for up to ten minutes of use, though they make for large targets.`;
	let knife = `simply a 8.5 meter long knife, though additional weapons are under development.`;
	let armor8 = ``;
	let actuator = ``;
	let cannon1 = ``;
	let heatsink = ``;
	let ammo2 = ``;
	let missile = ``;

	let a4 = `A cruise missile launch site has been constructed near the base of`;
	let b2 = `outdated, something quickly rigged together to give the launch site something to fire in the case of an attack`;
	let c8 = ``;
	let d1 = ``;
	let e1 = ``;
	let f1 = ``;
	let g1 = ``;
	let h1 = ``;

	let recom1 = `has been recommissioned from the old world for ${V.SF.Lower}. It`;
	let jets = `Formerly mothballed strike jets`;
	let radar = ``;
	let AAG = ``;
	let prop = ``;
	let torp = ``;
	let armor9 = ``;
	let power1 = ``;
	let scramble1 = ``;

	let recom = `has been recommissioned from the old world, and`;
	let reactor0 = `Because diesel engines provide power and breathing oxygen is kept in pressurized canisters, the sub must frequently surface.`;
	let reactor1 = ``;
	let cal = ``;
	let hull = ``;
	let tubes = ``;
	let torpedoes = ``;
	let sonar = ``;
	let control = ``;
	let missiles = ``;

	let recom2 = `has been recommissioned for use by ${V.SF.Lower}. It `;
	let tons = `200`;
	let skirt = ``;
	let guns = ``;
	let guns2 = ``;
	let fans = ``;
	let speed = ``;
	let turbines = ``;
	let armor10 = ``;
	let ramps = ``;
	let HATframe = ``;
	let loadout = ``;

	let loc2 = ``;
	if (V.week % 6 === 0) {
		loc2 += `is`;
		if (input !== 'HAT') {
			loc2 += ` moored to`;
		} else {
			loc2 += ` parked on`;
		}
		loc2 += ` the pier in the Naval Yard`;
		if (input === 'HAT') {
			loc2 += `, ready to ferry ${tons} tons of soldiers and vehicles`;
		}
	} else {
		loc2 += `is patrolling the waters near ${V.arcologies[0].name}`;
	}
	switch (input) {
		case 'firebase':
			if (S.Firebase >= 0) {
				const text0 = `<b>Firebase:</b>`;
				if (S.Firebase >= 1) {
					appear = `has had some organization put into it.`;
					barracks = `The majority of weapons, armor, and ammunition have been separated from the soldiers' cots into their own armory.`;
					garage = `A section near the outer wall of the arcology has been converted to a garage with an adjoining vehicle maintenance bay`;
					drone = `.`;
				}
				if (V.terrain === "oceanic") {
					garage += ` for inter-arcology travel`;
				}
				if (S.Firebase >= 2) {
					barracks = `A barracks has been constructed near the armory, allowing soldiers a quieter place to sleep and store their personal spoils.`;
					drone = `; as well as a facility for the storage, maintenance, and deployment of armed combat drones.`;
				}
				if (S.Firebase >= 3) {
					appear = `has become more permanent.`;
					barracks = `A command center has been constructed near the barracks and armory, allowing for additional support personnel.`;
				}
				if (S.Firebase >= 4) {
					hangar = `Hangar space for storing and repairing aircraft has been converted from unused space on the other side of the garage.`;
				}
				if (S.Firebase >= 5) {
					appear = `is nearing the appearance of a military base.`;
					launch = `The rest of the Firebase has been designated for special projects.`;
					artillery = `Artillery batteries are set around the base of the arcology.`;
				}
				if (V.terrain === "oceanic" || V.terrain === "marine") {
					launch += ` A Naval Yard has been constructed in the waters near the arcology.`;
				}
				if (S.Firebase >= 6) {
					common = `and in the center is a common area for recreation, including a small movie theater and a mess hall.`;
				}
				if (S.Firebase >= 7) {
					slave = `A slave detention facility has been sectioned off to one side`;
					if (V.SF.Depravity > 1.5) {
						slave += ` emanating the sounds of rape and torture`;
					}
					slave += `;`;
				}
				if (S.Firebase >= 8) {
					appear = `has become a fully fledged military base.`;
					comms = `A Free City-wide communication network for ${V.SF.Lower} has been constructed to facilitate faster responses and efficient monitoring of the surrounding area.`;
				}
				if (S.Firebase >= 9) {
					training = `A high-tech killhouse has been constructed to aid in soldier training.`;
				}
				if (S.Firebase >= 10) {
					artillery = `Railgun artillery batteries are set around the base of the arcology, capable of accurately destroying enemies an absurd distance away.`;
				}
				return `${text0} The firebase ${appear} ${barracks} ${comms} ${training} ${slave} ${common} ${garage}${drone} ${hangar} ${launch} ${artillery}`;
			}
			break;
		case 'troop':
			if (V.SF.ArmySize > 0) {
				const text1 = `<br> The large dormitories are`;
				if (V.SF.ArmySize < 100) {
					return `${text1} sparsely occupied, ${Quantity} residing within them concentrating together in a corner. The hundreds of empty beds and lockers visibly herald the future.`;
				} else if (V.SF.ArmySize < 400) {
					return `${text1} lightly occupied, with ${Quantity} starting to spread out across them.`;
				} else if (V.SF.ArmySize < 800) {
					return `${text1} moderately occupied, though ${Quantity} residing within have a considerable amount of extra room.`;
				} else if (V.SF.ArmySize < 1500) {
					return `${text1} well-occupied, and ${Quantity} residing within have started to form small cliques based on section and row.`;
				} else {
					return `${text1} near capacity, and ${Quantity} often barter their personal loot, whether it be monetary or human, for the choicest bunks.`;
				}
			}
			break;
		case 'Armoury':
			if (S.Armoury >= 0) {
				const text2 = `<br><b>Armoury:</b><br>`;
				if (S.Armoury >= 2) {
					radio = `Radios have been wired into the soldiers helmets`;
					helmets = `.`;
				}
				if (S.Armoury >= 2) {
					helmets = ` and a HUD has been integrated into the soldier's eyewear.`;
				}
				if (S.Armoury >= 3) {
					ammo0 = `Tactical vests have been provided, allowing soldiers to carry additional ammo.`;
				}
				if (S.Armoury >= 4) {
					armor1 = `The body armor is a newer variant, able to stop small arms fire and protect against shrapnel.`;
				}
				if (S.Armoury >= 5) {
					weapons = `The weapons are modern rifles and sidearms, putting ${V.SF.Lower} on par with rival mercenary outfits.`;
				}
				if (S.Armoury >= 6) {
					uniforms = `New uniforms have been distributed that are more comfortable and made of breathable fabric to keep soldiers from overheating.`;
				}
				if (S.Armoury >= 7) {
					special = `Specialized weaponry is available for many roles, allowing more flexibility in planning.`;
				}
				if (S.Armoury >= 8) {
					helmets = `and a HUD and camera display have been integrated into soldiers' eyewear, enabling accurate aim around corners or from behind cover.`;
				}
				if (S.Armoury >= 9) {
					exo = `An exosuit has been developed to reduce the amount of weight soldiers carry, increase lifting strength, and move faster in combat.`;
				}
				if (S.Armoury >= 10) {
					weapons = `Cutting-edge weaponry is available to ${V.SF.Lower}, far outpacing the ability of rival mercenary outfits.`;
				}
				return `${text2} The armory holds soldiers' weapons and gear while not in training or combat. ${weapons} ${special} ${armor1} ${radio} ${helmets} ${ammo0} ${uniforms} ${exo}`;
			}
			break;
		case 'drugs':
			if (S.Drugs >= 0) {
				const text3 = `<br><b>Drug Lab:</b>`;
				if (S.Drugs >= 2) {
					amphet = `Amphetamines have been added to the cocktail at a low dosage to act as a stimulant, physical performance enhancer, and cognition control enhancer. Some side-effects exist.`;
				}
				if (S.Drugs >= 2) {
					phen = `Phencyclidine has been added to the cocktail at a low dosage as a dissociative psychotropic for soldiers in battle to introduce feelings of detachment, strength and invincibility, and aggression. Some side-effects reduce the tolerable dosage before soldiers go on uncontrollable violent outbreaks.`;
				}
				if (S.Drugs >= 3) {
					steroid = `Testosterone is being produced for soldiers in training as a natural muscle growth stimulant and to invoke aggression.`;
				}
				if (S.Drugs >= 4) {
					downer = `Zaleplon is being produced as a downer to counteract the battle cocktail and encourage rest before combat.`;
				}
				if (S.Drugs >= 5) {
					concen = `Methylphenidate has been added to the cocktail as a stimulant and to improve soldier concentration.`;
				}
				if (S.Drugs >= 6) {
					phen = `A phencyclidine-based drug has been added to the cocktail as a dissociative psychotropic for soldiers in battle to introduce controllable feelings of detachment, strength and invincibility, and aggression.`;
				}
				if (S.Drugs >= 7) {
					steroid = `Low levels of anabolic steroids are being produced for soldiers in training to stimulate muscle growth and invoke aggression.`;
				}
				if (S.Drugs >= 8) {
					amphet = `Diphenylmethylsulfinylacetamide has been added to the cocktail to counteract the effects of sleep deprivation and promote alertness.`;
				}
				if (S.Drugs >= 9) {
					stimpack = `A stimpack of the battle cocktail is being given to soldiers in battle to take if the original dose wears off before the battle is over.`;
				}
				if (S.Drugs >= 10) {
					stabilizer = `A stabilizer has been added to the battle cocktail that helps tie effects together while reducing side-effects, leading to an effectively safe supersoldier drug.`;
				}
				return `${text3} A drug lab has been established to increase the effectiveness of ${V.SF.Lower}'s soldiers. Many of these chemicals are mixed into a single 'battle cocktail' to be taken before combat. ${amphet} ${phen} ${concen} ${steroid} ${downer} ${stimpack} ${stabilizer}`;
			}
			break;
		case 'UAV':
			if (S.Firebase >= 2 && S.Drones >= 1) {
				const text4 = `<br><b>Drone Bay:</b>`;
				if (S.Drones >= 2) {
					a = `equipped with missiles are resting on one side of the drone bay`;
					b = `; as well as destroying the occasional target.`;
				}
				if (S.Drones >= 3) {
					c = `A fleet of`;
					d = `large delivery quadcopters have been converted for military service to support ground forces as combat drones.`;
				}
				if (S.Drones >= 4) {
					d = `combat drones take up the rest of the space in the drone bay. They have a`;
					e = `small automatic rifle`;
					f = `mounted to the underside.`;
				}
				if (S.Drones >= 5) {
					g = `Armor has been added to protect vulnerable components from small arms fire.`;
				}
				if (S.Drones >= 6) {
					h = `The fleet's batteries have been replaced with higher capacity models, increasing the functional time spent in combat.`;
				}
				if (S.Drones >= 7) {
					i = `The propellers and motors have been upgraded, increasing maneuverability and speed.`;
				}
				if (S.Drones >= 8) {
					j = `The drone control signal has been boosted and encrypted, giving the drones a greater range and protecting against electronic warfare.`;
				}
				if (S.Drones >= 9) {
					e = `light machine gun`;
				}
				if (S.Drones >= 10) {
					k = `A drone-to-drone network has been installed, allowing drones to swarm, maneuver, and attack targets autonomously.`;
				}
				text += `${text4} Surveillance drones ${a}. During combat, they supply aerial intel to commanders and act as the communications network for ground forces${b} ${c} ${d} ${e} ${f} ${g} ${h} ${i} ${j} ${k}`;
			}
			return text;
		case 'AV':
			if (S.AV >= 1) {
				const text5 = `<br>  <b>Assault:</b>`;
				if (S.AV >= 2) {
					engine1 = `The engine has been overhauled, allowing much faster maneuvering around the battlefield.`;
					activate = ``;
					mechanics = ``;
				}
				if (S.AV >= 3) {
					armor2 = `A composite ceramic armor has replaced the original, offering much greater protection from attacks.`;
				}
				if (S.AV >= 4) {
					ammo1 = `The tanks have been outfitted with additional types of ammo for situational use.`;
				}
				if (S.AV >= 5) {
					mg = `A remote-controlled .50 cal machine gun has been mounted on the turret to handle infantry and low-flying aircraft.`;
				}
				if (S.AV >= 6) {
					fireC0 = `A fire-control system`;
					fireC3 = `been installed, guaranteeing`;
					fireC2 = `has`;
					fireC1 = `accurate fire.`;
				}
				if (S.AV >= 7) {
					fireC1 = `rapid, accurate fire while separating the crew from the stored ammunition in the event the ammo cooks off.`;
					fireC2 = `and an autoloader have`;
				}
				if (S.AV >= 8) {
					armor22 = `A reactive armor system has been added, giving the tank an additional, if temporary, layer of protection.`;
				}
				if (S.AV >= 9) {
					turret = `The turret has been massively redesigned, lowering the tank profile and increasing the efficiency of the mechanisms within.`;
				}
				if (S.AV >= 10) {
					MG = `140 mm main gun can quash anything even the greatest old world nations could muster.`;
				}
				text += `${text5} A fleet of main battle tanks ${activate} are parked in the garage${mechanics}. ${turret} The ${MG} ${ammo1} ${mg} ${fireC0} ${fireC2} ${fireC3} ${fireC1} ${engine1} ${armor2} ${armor22}`;
			}
			return text;
		case 'TV':
			if (S.TV >= 1) {
				const text6 = `<br>  <b>Transport:</b>`;
				if (S.TV >= 2) {
					engine3 = `${e0} overhauled, allowing for higher mobility.`;
					C = ``;
					B = ``;
				}
				if (S.TV >= 3) {
					armor3 = `Composite armor has been bolted to the exterior, increasing the survivability of an explosive attack for the crew and passengers.`;
				}
				if (S.TV >= 4) {
					tires = `The tires have been replaced with a much more durable version that can support a heavier vehicle.`;
				}
				if (S.TV >= 5) {
					m1 = `An automatic missile defense system has been installed,`;
					m2 = `targeting any guided missiles with laser dazzlers and deploying a smokescreen.`;
				}
				if (S.TV >= 6) {
					pod1 = `An anti-tank missile pod`;
					pod2 = `has been installed on the side of the turret.`;
				}
				if (S.TV >= 7) {
					G1 = `25`;
					G2 = `by attacking enemies through cover and destroying light armor`;
				}
				if (S.TV >= 8) {
					pod2 = `and an anti-aircraft missile pod have been installed on either side of the turret.`;
				}
				if (S.TV >= 9) {
					squad = `two squads`;
					armor3 = ``;
					m2 = `destroying any incoming missiles with a high-powered laser. Some of the now redundant composite armor has been removed, and the reclaimed space allows for more passengers.`;
				}
				if (S.TV >= 10) {
					engine3 = `${e0} replaced with the newest model, allowing the vehicle to get in and out of the conflict extremely quickly.`;
				}
				text += `${text6} A fleet of infantry fighting vehicles ${B} are parked in the garage${C}. The IFVs can carry ${squad} of 6 to a firezone. The ${G1} mm autocannon supports infantry ${G2}. ${pod1} ${pod2} ${engine3} ${armor3} ${tires} ${m1} ${m2}`;
			}
			return text;
		case 'PGT':
			if (S.PGT >= 1) {
				const text7 = `<br> <b>Prototype Goliath Tank:</b>`;
				if (S.PGT >= 2) {
					c1 = `rests in`;
					b1 = ``;
					engines4 = ` and powered by their own engine, allowing the tank to travel with an unsettling speed for its massive bulk`;
				}
				if (S.PGT >= 3) {
					gun0 = `a railgun capable of`;
					gun1 = `firing steel slugs`;
					gun2 = `through one tank and into another`;
				}
				if (S.PGT >= 4) {
					armor5 = `The armor has been`;
					armor6 = `reinforced, increasing survivability for the crew inside.`;
				}
				if (S.PGT >= 5) {
					cannon = `A coaxial 30mm autocannon has been installed in the turret, along with automated .50 cal machine guns mounted over the front treads.`;
				}
				if (S.PGT >= 6) {
					laser = `Laser anti-missile countermeasures have been installed, destroying any subsonic ordinance fired at the Goliath.`;
				}
				if (S.PGT >= 7) {
					PGTframe = `The frame has been reinforced, allowing the Goliath to carry more armor and guns.`;
				}
				if (S.PGT >= 8) {
					armor6 = `redesigned with sloping and state-of-the-art materials, allowing the Goliath to shrug off even the most advanced armor-piercing tank rounds.`;
				}
				if (S.PGT >= 9) {
					gun1 = `firing guided projectiles`;
				}
				if (S.PGT >= 10) {
					gun0 = `a twin-barreled railgun capable of rapidly`;
				}
				text += `${text7} A prototype Goliath tank ${b1}${c1} its own garage housing built outside the arcology. The massive bulk is spread out over 8 tracks, two for each corner of the tank${engines4}. The turret is equipped with ${gun0} ${gun1} ${gun2}. ${cannon} ${armor5} ${armor6} ${laser} ${PGTframe}`;
			}
			return text;
		case 'AA':
			if (S.AA >= 1) {
				const text8 = `<br>  <b>Assault:</b>`;
				if (S.AA >= 2) {
					W1 = `armed`;
					W2 = ` and air-to-air missiles,`;
					W3 = `a combination that can defend the arcology from enemy aircraft, as well as`;
					support = ` support ground troops`;
				}
				if (S.AA >= 3) {
					engines = `The engines have been tuned, allowing faster flight with greater acceleration.`;
				}
				if (S.AA >= 4) {
					TAI = `An advanced targeting AI has been installed to handle all control of weapons, allowing much more efficient use of ammunition and anti-countermeasure targeting.`;
				}
				if (S.AA >= 5) {
					lock = `Installed multispectrum countermeasures protect against all types of missile locks.`;
				}
				if (S.AA >= 6) {
					group = `A respectable number of attack VTOL protect your arcology, split into a few squadrons`;
				}
				if (S.AA >= 7) {
					support = ` attack ground targets`;
					W2 = `; rocket pods, and air-to-air missiles,`;
				}
				if (S.AA >= 8) {
					stealth = `The old skin has been replaced with a radar-absorbent material, making the aircraft difficult to pick up on radar.`;
				}
				if (S.AA >= 9) {
					scramble = `The VTOLs can scramble to react to any threat in under three minutes.`;
				}
				if (S.AA >= 10) {
					PAI = `A piloting AI has been installed, allowing the VTOLs to perform impossible maneuvers that cannot be done by a human pilot. This removes the need for a human in the aircraft altogether.`;
				}
				text += `${text8} ${group}. Several of the landing pads around ${V.arcologies[0].name} host groups of four fighters, ready to defend the arcology. ${scramble} The attack VTOL are currently ${W1} with a Gatling cannon${W2} ${W3}${support}. ${TAI} ${PAI} ${engines} ${lock} ${stealth}`;
			}
			return text;
		case 'TA':
			if (S.TA >= 1) {
				const text9 = `<br>  <b>Transport:</b>`;
				if (S.TA >= 2) {
					engines0 = `The tiltrotor engines have been replaced with a more powerful engine, allowing faster travel times.`;
				}
				if (S.TA >= 3) {
					counter = `Multispectrum countermeasures have been added to protect against guided missiles.`;
				}
				if (S.TA >= 4) {
					miniguns = `Mounted miniguns have been installed to cover soldiers disembarking in dangerous areas.`;
				}
				if (S.TA >= 5) {
					Num = `large number`;
				}
				if (S.TA >= 6) {
					landing = `The landing equipment has been overhauled, protecting personnel and cargo in the event of a hard landing or crash.`;
				}
				if (S.TA >= 7) {
					Armor = `Armor has been added to protect passengers from small arms fire from below.`;
				}
				if (S.TA >= 8) {
					capacity = `large platoon or 20`;
					engines01 = `Further tweaks to the engine allow for greater lifting capacity.`;
				}
				if (S.TA >= 9) {
					Radar = `Radar-absorbent materials have replaced the old skin, making it difficult to pick up the VTOL on radar.`;
				}
				if (S.TA >= 10) {
					type = `tiltjet`;
					engines01 = ``;
					engines0 = `The tiltrotors have been replaced with tiltjets, allowing for much greater airspeed and acceleration.`;
				}
				text += `${text9} A ${Num} of transport ${type} VTOL have been recommissioned for use by ${V.SF.Lower}. The VTOLs are resting on large pads near the base, ready to load either a ${capacity} tons of material. ${engines0} ${engines01} ${Armor} ${landing} ${counter} ${Radar} ${miniguns}`;
			}
			return text;
		case 'SP':
			if (S.SpacePlane >= 1) {
				const text10 = `<br> <b>Spaceplane:</b>`;
				if (S.SpacePlane >= 2) {
					b5 = ``;
					shield = `The current heat shielding has been upgraded, reducing the likelihood of heat damage during reentry.`;
				}
				if (S.SpacePlane >= 3) {
					engine2 = ` and liquid rocket engines in orbit that can reach an equivalent Mach 18`;
				}
				if (S.SpacePlane >= 4) {
					camera = `A state-of-the-art camera has been installed in the underbelly that takes incredibly high resolution photos, but requires the frictionless environment of space to focus.`;
				}
				if (S.SpacePlane >= 5) {
					efficiency = `Tweaks to the engines have increased fuel efficiency to the point where midflight refueling is no longer necessary.`;
				}
				if (S.SpacePlane >= 6) {
					camera2 = `The camera sensor is capable of taking IR shots.`;
				}
				if (S.SpacePlane >= 7) {
					drag = `Miraculous advances in aerodynamics and materials allow frictionless flight, even while in the atmosphere.`;
				}
				if (S.SpacePlane >= 8) {
					crew = `Increased the crew comfort and life support systems to increase operational time.`;
				}
				if (S.SpacePlane >= 9) {
					skin = `Replaced the underbelly skin with a chameleon kit, matching the color to the sky above it.`;
				}
				if (S.SpacePlane >= 10) {
					engine2 = ` and liquid rocket engines in orbit that can reach an equivalent Mach 25`;
					engine20 = `experimental scramjet engines in the atmosphere that can reach Mach 15`;
				}
				text += `${text10} A prototype spaceplane ${b5} rests in the hangar, its black fuselage gleaming. The craft is powered by ${engine20}${engine2}. ${efficiency} ${shield} ${camera} ${camera2} ${drag} ${crew} ${skin}`;
			}
			return text;
		case 'GunS':
			if (S.GunS >= 1) {
				const text11 = `<br> <b>Gunship:</b>`;
				if (S.GunS >= 2) {
					b4 = `Infrared sensors have been added for the gunners to better pick targets.`;
					activate2 = ``;
				}
				if (S.GunS >= 3) {
					c2 = `The underside of the aircraft has been better armored against small-arms fire`;
					countermeasures = `.`;
				}
				if (S.GunS >= 4) {
					fuel = `Larger fuel tanks have been installed in the wings and fuselage, allowing the gunship to provide aerial support for longer periods before refueling.`;
				}
				if (S.GunS >= 5) {
					barrels = `25 mm Gatling cannons`;
					distance = `; allowing the gunship to eliminate infantry`;
					DFA = ` and light vehicles from above`;
					autocannon = ` and a 40 mm autocannon are mounted on`;
				}
				if (S.GunS >= 6) {
					gsSpeed = `The engines have been replaced, allowing both faster travel to a target, and slower travel around a target.`;
				}
				if (S.GunS >= 7) {
					countermeasures = `; and multi-spectrum countermeasures have been installed to protect against guided missiles.`;
				}
				if (S.GunS >= 8) {
					b4 = `Upgraded multi-spectrum sensors can clearly depict targets even with IR shielding.`;
				}
				if (S.GunS >= 9) {
					ammunition = `The ammunition storage has been increased, only slightly depriving loaders of a place to sit.`;
				}
				if (S.GunS >= 10) {
					DFA = `; both light and heavy vehicles, and most enemy cover from above`;
					autocannon = `; a 40 mm autocannon, and a 105 mm howitzer are mounted on`;
				}
				text += `${text11} A large gunship ${activate2} is being refueled in the hangar. ${barrels}${autocannon} the port side of the fuselage${distance}${DFA}. ${b4} ${ammunition} ${gsSpeed} ${c2}${countermeasures} ${fuel}`;
			}
			return text;
		case 'sat':
			if (S.Satellite >= 1) {
				const text12 = `<br> <b>Satellite:</b>`;
				if (S.Satellite >= 2) {
					if (V.SF.SatLaunched === 0) {
						loc1 = `The satellite is being worked on in the Launch Bay.`;
					} else {
						loc1 = `The satellite is in geosynchronous orbit, far above the arcology.`;
					}
					gyro = `A suite of sensors have been installed to ensure the satellite can detect attitude and orbital altitude.`;
				}
				if (S.Satellite >= 3) {
					telemetry = `Telemetry systems have been installed to communicate with the satellite in orbit, with strong encryption measures.`;
				}
				if (S.Satellite >= 4) {
					thrusters = `Thrusters have been installed to control satellite attitude and orbit.`;
				}
				if (S.Satellite >= 5) {
					solar = `A massive folding solar panel array, combined with the latest in battery technology allow the satellite to store an enormous amount of energy relatively quickly.`;
					surviv = `Enough of the satellite has been finished that it can expect to survive for a significant period of time in space.`;
				}
				if (S.Satellite >= 6) {
					laser1 = `A laser cannon has been mounted facing the earth, capable of cutting through steel in seconds`;
					heat = ` while generating a large amount of heat.`;
				}
				if (S.Satellite >= 7) {
					heat = `. The installed heatsink allows the laser cannon to fire more frequently without damaging the satellite.`;
				}
				if (S.Satellite >= 8) {
					reactor = `A small, efficient nuclear reactor has been installed to continue generating energy while in the Earth's shadow.`;
				}
				if (S.Satellite >= 9) {
					lens = `A higher quality and adjustable lens has been installed on the laser, allowing scalpel precision on armor or wide-area blasts on unarmored targets.`;
				}
				if (S.Satellite >= 10) {
					kin = `A magazine of directable tungsten rods have been mounted to the exterior of the satellite, allowing for kinetic bombardment roughly equal to a series of nuclear blasts.`;
				}
				text += `${text12} ${loc1} ${gyro} ${thrusters} ${telemetry} ${solar} ${reactor} ${surviv} ${laser1} ${heat} ${lens} ${kin}`;
			}
			return text;
		case 'GR':
			if (S.GiantRobot >= 1) {
				const text13 = `<br> <b>Giant Robot:</b>`;
				if (S.GiantRobot >= 2) {
					loc = ``;
					armor8 = `Armor plating has been mounted over the majority of the robot.`;
				}
				if (S.GiantRobot >= 3) {
					power = `The robot is now powered by an umbilical cable system instead of bulky and short-lived batteries.`;
				}
				if (S.GiantRobot >= 4) {
					knife = `a 25 meter plasma sword. The cutting edge uses plasma to melt and cut through targets, reducing the strain on the sword.`;
				}
				if (S.GiantRobot >= 5) {
					actuator = `The limb actuators have been replaced with a faster and more powerful variant, granting the robot the same.`;
				}
				if (S.GiantRobot >= 6) {
					cannon1 = `A custom 45 mm Gatling cannon rifle has been developed for ranged use`;
					ammo2 = `; though it lacks enough ammo storage for a main weapon.`;
				}
				if (S.GiantRobot >= 7) {
					heatsink = `Large heatsinks have been installed out of the back to solve a massive overheating problem. These heatsinks resemble wings, and tend to glow red with heat when in heavy use.`;
				}
				if (S.GiantRobot >= 8) {
					armor8 = ``;
					actuator = `Final actuator tweaks have allowed for the addition of exceptionally thick armor without any loss in speed or power.`;
				}
				if (S.GiantRobot >= 9) {
					ammo2 = `; with spare ammunition drums kept along the robot's waist.`;
				}
				if (S.GiantRobot >= 10) {
					missile = `Missile pods have been mounted on the shoulders.`;
				}
				text += `${text13} A prototype giant robot ${loc} rests in a gantry along the side of the arcology. The robot is as tall as a medium-sized office building, focusing on speed over other factors. ${power} ${armor8} ${actuator} ${heatsink} The main armament is ${knife} ${cannon1}${ammo2} ${missile}`;
			}
			return text;
		case 'ms':
			if (S.MissileSilo >= 1) {
				const text14 = `<br> <b>Cruise Missile:</b>`;
				if (S.MissileSilo >= 2) {
					b2 = `a modern missile`;
					c8 = `; tipped with a conventional warhead`;
				}
				if (S.MissileSilo >= 3) {
					d1 = `The launch systems have been overhauled, allowing a launch within seconds of an attack order being given.`;
				}
				if (S.MissileSilo >= 4) {
					e1 = `The missile engines have been tweaked, giving them a greater range.`;
				}
				if (S.MissileSilo >= 5) {
					f1 = `A passive radar has been installed, allowing the missile to follow moving targets.`;
				}
				if (S.MissileSilo >= 6) {
					a4 = `Several cruise missile launch sites have been constructed around`;
				}
				if (S.MissileSilo >= 7) {
					e1 = `The engine has been replaced, giving the missiles greater range and supersonic speeds.`;
				}
				if (S.MissileSilo >= 8) {
					g1 = `The ability to pick new targets should the original be lost has been added.`;
				}
				if (S.MissileSilo >= 9) {
					h1 = `The missile now uses its remaining fuel to create a thermobaric explosion, massively increasing explosive power.`;
				}
				if (S.MissileSilo >= 10) {
					c8 = ` that can be tipped with either a conventional or nuclear warhead`;
				}
				text += `${text14} ${a4} the arcology. The current missile armament is ${b2}${c8}. ${d1} ${e1} ${f1} ${g1} ${h1}`;
			}
			return text;
		case 'AC':
			if (S.AircraftCarrier >= 1) {
				const text15 = `<br> <b>Aircraft Carrier:</b>`;
				if (S.AircraftCarrier >= 2) {
					radar = `The island's radar and comms have been improved.`;
					recom1 = ``;
				}
				if (S.AircraftCarrier >= 3) {
					AAG = `The antiair guns have been updated to automatically track and predict enemy aircraft movement.`;
				}
				if (S.AircraftCarrier >= 4) {
					jets = `Modern strike jets with state-of-the-art armaments`;
				}
				if (S.AircraftCarrier >= 5) {
					prop = `The propellers have been redesigned, granting greater speed with less noise.`;
				}
				if (S.AircraftCarrier >= 6) {
					torp = `An anti-torpedo system detects and destroys incoming torpedoes.`;
				}
				if (S.AircraftCarrier >= 7) {
					armor9 = `Additional armor has been added to the hull and deck.`;
				}
				if (S.AircraftCarrier >= 8) {
					power1 = `The power plant has been converted to provide nuclear power.`;
				}
				if (S.AircraftCarrier >= 9) {
					scramble1 = `The catapult has been converted to an electromagnetic launch system, halving the time it takes to scramble jets.`;
				}
				if (S.AircraftCarrier >= 10) {
					jets = `Attack VTOL from the converted for carrier capability`;
				}
				text += `${text15} An aircraft carrier ${recom1} ${loc2}. ${jets} serve as its airpower. ${scramble1} ${power1} ${radar} ${AAG} ${torp} ${prop} ${armor9}`;
			}
			return text;
		case 'Sub':
			if (S.Sub >= 1) {
				const text16 = `<br> <b>Submarine:</b>`;
				if (S.Sub >= 2) {
					recom = ``;
					reactor0 = `A nuclear reactor provides power`;
					reactor1 = `; but because oxygen is still kept in pressurized canisters the sub must frequently surface to replenish its oxygen stocks.`;
				}
				if (S.Sub >= 3) {
					reactor1 = ` and an oxygen generator pulls O₂ from the surrounding seawater, allowing the submarine to remain underwater for months if necessary.`;
				}
				if (S.Sub >= 4) {
					cal = `Calibration of the propulsion systems has reduced the telltale hum of a moving sub to a whisper.`;
				}
				if (S.Sub >= 5) {
					hull = `The outer hull has been redesigned for hydrodynamics and sonar absorption.`;
				}
				if (S.Sub >= 6) {
					tubes = `The torpedo tubes have been redesigned for faster loading speeds`;
					torpedoes = `.`;
				}
				if (S.Sub >= 7) {
					sonar = `The passive sonar has been finely tuned to detect mechanical noises miles away.`;
				}
				if (S.Sub >= 8) {
					control = `The control room computers have been upgraded to automate many conn duties.`;
				}
				if (S.Sub >= 9) {
					torpedoes = `and launch more agile torpedoes.`;
				}
				if (S.Sub >= 10) {
					missiles = `The submarine has been outfitted with several cruise missiles to attack land or sea-based targets.`;
				}
				text += `${text16} An attack submarine ${recom} ${loc2}. ${reactor0}${reactor1} ${cal} ${hull} ${tubes}${torpedoes} ${sonar} ${control} ${missiles}`;
			}
			return text;
		case 'HAT':
			if (S.HAT >= 1) {
				const text17 = `<br> <b>Amphibious Transport:</b>`;
				if (S.HAT >= 2) {
					skirt = `The skirt has been upgraded to increase durability and improve cushion when traveling over uneven terrain and waves.`;
					recom2 = ``;
				}
				if (S.HAT >= 3) {
					guns = `A minigun`;
					guns2 = `has been mounted on the front corners of the craft to defend against attackers.`;
				}
				if (S.HAT >= 4) {
					fans = `The turbines powering the rear fans`;
					speed = `acceleration and speed.`;
					turbines = `have been replaced with a more powerful version, allowing greater`;
				}
				if (S.HAT >= 5) {
					armor10 = `The armor protecting its cargo has been increased.`;
				}
				if (S.HAT >= 6) {
					fans = `The turbines powering the rear fans and impeller`;
					speed = `acceleration, speed, and carrying capacity.`;
				}
				if (S.HAT >= 7) {
					guns = `A minigun and grenade launcher`;
				}
				if (S.HAT >= 8) {
					ramps = `The loading ramps have been improved, allowing for faster unloading.`;
				}
				if (S.HAT >= 9) {
					HATframe = `The frame has been widened and reinforced, allowing for more space on the deck.`;
				}
				if (S.HAT >= 10) {
					loadout = `An experimental loadout sacrifices all carrying capacity to instead act as a floating gun platform by mounting several rotary autocannons the deck, should the need arise.`;
				}
				text += `${text17} An air cushion transport vehicle, or hovercraft; ${recom2}${loc2}. ${guns} ${guns2} ${fans} ${turbines} ${speed} ${skirt} ${armor10} ${ramps} ${HATframe} ${loadout}`;
			}
			return text;
	}
};


code:
App.UI.manageArcology = function() {
	const frag = new DocumentFragment();

	V.nextButton = "Back";
	V.nextLink = "Main";
	V.encyclopedia = "The X-Series Arcology";

	const arcologyName = V.arcologies[0].name;

	frag.append(
		description(),
		ownership(),
		construction(),
		weather(),
		sexualServices(),
		language(),
		upgrades(),
		records(),
	);

	if (V.eventResults.foodCrisis) {
		frag.append(
			foodMarket()
		);
	}

	if (V.secExpEnabled) {
		frag.append(
			security(),
			military(),
		);
	}

	if (V.experimental.dinnerParty === 1 && V.seeExtreme === 1) {
		frag.append(
			events(),
		);
	}

	return frag;

	function description() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		if (V.cheatMode === 1) {
			App.UI.DOM.appendNewElement("div", div,
				App.UI.DOM.passageLink(`Cheat Edit Arcology`, "MOD_Edit Arcology Cheat"),
				["cheat-menu"]);
		}

		App.UI.DOM.appendNewElement("h1", div,
			App.UI.DOM.link(`${V.arcologies[0].name}`, () => {
				if (Dialog.isOpen()) {
					Dialog.close();
				}
				Dialog.setup("Rename");

				const frag = new DocumentFragment();

				frag.append(App.UI.DOM.makeTextBox(V.arcologies[0].name, str => { V.arcologies[0].name = str; App.UI.reload(); }));
				$(Dialog.body()).empty().append(frag);
				Dialog.open();
			})
			, ["white", "center"]
		);

		App.UI.DOM.appendNewElement("div", div, V.building.render());

		if (V.seeArcology === 1) {
			div.append(App.Desc.playerArcology(
				App.UI.DOM.link(`Hide`, () => {
					V.seeArcology = 0;
					App.UI.reload();
				})
			));
		}

		return div;
	}

	function ownership() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.Arcology.updateOwnership();

		App.UI.DOM.appendNewElement("h2", div, "Arcology Ownership");
		div.append(ownershipReport(false));

		if (FutureSocieties.availCredits() > 0) {
			App.UI.DOM.appendNewElement("span", div, ` Society is ready to begin accepting a new societal direction.`, ['noteworthy']);
		}

		return div;
	}

	function construction() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Construction");

		if (V.arcologyUpgrade.drones !== 1) {
			App.UI.DOM.appendNewElement("div", div, `The first major upgrade needed is the installation of a drone security system so higher-class citizens will feel safe and protected should they choose to immigrate.`);
			div.append(makePurchase(`Install drone security system`, 5000 * V.upgradeMultiplierArcology, "capEx", {
				notes: [`increases upkeep`],
				handler: () => {
					V.arcologyUpgrade.drones = 1;
					V.PC.skill.engineering++;
				},
			}));
		} else {
			App.UI.DOM.appendNewElement("div", div, `A drone-based security system has been installed throughout ${arcologyName}.`);

			if (V.arcologyUpgrade.hydro !== 1) {
				App.UI.DOM.appendNewElement("div", div, `The next major upgrade needed is the installation of a better water reclamation system so your residents will have access to cheaper water and hydroponically grown food.`);
				div.append(makePurchase(`Upgrade water reclamation system`, 10000 * V.upgradeMultiplierArcology, "capEx", {
					notes: [`increases upkeep`],
					handler: () => {
						V.arcologyUpgrade.hydro = 1;
						V.PC.skill.engineering++;
					},
				}));
			} else {
				App.UI.DOM.appendNewElement("div", div, `Large pipes from the advanced water reclamation system can occasionally be seen snaking their way through the plumbing system.`);

				if (V.arcologyUpgrade.apron !== 1) {
					App.UI.DOM.appendNewElement("div", div, `The next major upgrade needed is the installation of a broader apron at the bottom of the arcology to increase its surface area and gather more solar energy. Right now, tenants that use a lot of power have to import it from outside.`);
					div.append(makePurchase(`Install solar apron`, 20000 * V.upgradeMultiplierArcology, "capEx", {
						notes: [`increases upkeep`],
						handler: () => {
							V.arcologyUpgrade.apron = 1;
							V.PC.skill.engineering++;
						},
					}));
				} else {
					App.UI.DOM.appendNewElement("div", div, `Huge swathes of solar panels are installed on the outside of ${arcologyName}, covering nearly everything that isn't glass or an entrance.`);

					if (V.arcologyUpgrade.grid !== 1) {
						App.UI.DOM.appendNewElement("div", div, `The next major upgrade needed is an improvement of the arcology's electrical transmission lines to make efficient use of the additional power from the solar apron.`);
						div.append(makePurchase(`Upgrade transmission lines`, 50000 * V.upgradeMultiplierArcology, "capEx", {
							notes: [`increases upkeep`],
							handler: () => {
								V.arcologyUpgrade.grid = 1;
								V.PC.skill.engineering++;
							},
						}));
					} else {
						App.UI.DOM.appendNewElement("div", div, `Thick cables as large as your forearm can be seen in the exposed ceilings of some parts of your arcology.`);
						App.UI.DOM.appendNewElement("div", div, App.Arcology.upgrades(V.building));
					}
				}
			}
		}

		const text = [];

		if (V.weatherCladding === 0) {
			text.push(`Extreme weather is becoming common worldwide. The arcology's exterior can be hardened to reduce damage in case of heavy weather, but this will reduce its beauty somewhat. Your citizens are`);

			if (V.weatherAwareness === 0) {
				text.push(`likely to disapprove of this measure as alarmism.`);
			} else {
				text.push(App.UI.DOM.makeElement("span", `concerned that this measure has not been taken already.`, ['noteworthy']));
			}

			App.Events.addNode(div, text, "div");

			div.append(makePurchase(`Apply weather cladding`, 50000 * V.upgradeMultiplierArcology, "capEx", {
				handler: () => {
					V.weatherCladding++;
					V.PC.skill.engineering++;
				},
			}));
		} else {
			text.push(`The arcology's exterior is jacketed with ${V.weatherCladding === 1 ? "unsightly but sturdy" : "gorgeously sculpted and fully functional"} weather cladding.`);

			App.Events.addNode(div, text, "div");

			if (V.weatherCladding === 1 && V.building.sections.length > 0) {
				div.append(
					`Your arcology is so prosperous that remodeling the cladding into something beautiful is within the realm of possibility. This massive project without a doubt render your arcology one of the wonders of the world.`,
					makePurchase(`Remodel weather cladding`, 3_500_000 * V.upgradeMultiplierArcology, "capEx", {
						handler: () => {
							V.weatherCladding++;
							V.PC.skill.engineering++;
						},
					})
				);
			}
		}

		if (V.FCTV.receiver > -1 && !V.FCTV.weekEnabled) {
			App.UI.DOM.appendNewElement("div", div, "You have not installed an FCTV receiver.");

			div.append(
				`You can purchase a receiver and cover the cost yourself.`,
				makePurchase(`No subsidy`, 25000 * V.upgradeMultiplierArcology, "capEx", {
					handler: () => {
						V.FCTV.receiver = 1;
						V.FCTV.weekEnabled = V.week;
						FCTV.initChannels();

						repX(500, "capEx");
					},
				}),
				`You can also have your citizens cover some of the cost, instead.`,
				makePurchase(`Minor subsidy`, 20000 * V.upgradeMultiplierArcology, "capEx", {
					handler: () => {
						V.FCTV.receiver = 1;
						V.FCTV.weekEnabled = V.week;
						FCTV.initChannels();
					},
				}),
				`You could also choose to have your citizens cover most of the cost.`,
				makePurchase(`Major subsidy`, 15000 * V.upgradeMultiplierArcology, "capEx", {
					notes: [`will upset your citizens`],
					handler: () => {
						V.FCTV.receiver = 1;
						V.FCTV.weekEnabled = V.week;
						FCTV.initChannels();

						repX(-1500, "capEx");
					},
				}),
			);
		} else {
			const text = [];

			text.push(`You have installed the FCTV receiver and have access to the full range of FCTV's programs.`);

			if (V.FCTV.receiver === 3) {
				text.push(`High viewership rates amongst your citizens makes it easier to pursue your societal goals.`);
			} else if (V.FCTV.receiver === 2) {
				text.push(`Decent viewership rates amongst your citizens makes it somewhat easier to pursue your societal goals.`);
			} else if (V.FCTV.receiver === 1) {
				text.push(`Low viewership rates amongst your citizens limits the impact of FCTV on your societal goals.`);
			}

			App.UI.DOM.appendNewElement("div", div, text.join(' '));
		}

		if (V.PC.skill.engineering >= 100 || V.PC.career === "arcology owner") {
			const innerDiv = App.UI.DOM.appendNewElement("div", div, "Arcology upgrades are less expensive due to your ");

			App.UI.DOM.appendNewElement("span", innerDiv, V.PC.career === "arcology owner" ? `experience in the Free Cities.` : `arcology engineering training.`, ["player", "skill"]);
		}

		return div;
	}

	function weather() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Weather");

		if (V.difficultySwitch === 1) {
			if (V.econWeatherDamage > 0) {
				div.append(
					`The recent terrible weather has damaged the local infrastructure. It is `,
					App.UI.DOM.makeElement("span", `reducing the local economy score by ${num(V.econWeatherDamage)}.`, ['warning'])
				);

				if (V.disasterResponse === 0) {
					div.append(
						` Locals will do their best to repair the damage on their own, but setting up a disaster response unit will improve the recovery of infrastructure critical for keeping goods, people and information flowing smoothly in and out of your arcology.`,
						makePurchase(`Create a disaster response unit`, 50000 * V.upgradeMultiplierArcology, "capEx", {
							notes: [`increases upkeep`],
							handler: () => {
								V.disasterResponse++;
								V.PC.skill.engineering++;
							}
						}),
					);
				} else if (V.disasterResponse === 1) {
					div.append(
						` You are sending your disaster response unit to repair critical infrastructure. They are doing what they can.`,
						makePurchase(`Purchase specialized all-weather equipment for the response unit`, 100_000 * V.upgradeMultiplierArcology, "capEx", {
							notes: [`increases upkeep`],
							handler: () => {
								V.disasterResponse++;
								V.PC.skill.engineering++;
							}
						}),
					);
				} else {
					App.UI.DOM.appendNewElement("div", div, "Your highly capable disaster response unit is rapidly repairing the weather damage.");
				}
			} else if (V.disasterResponse > 0) {
				App.UI.DOM.appendNewElement("div", div, "Your disaster response unit is idle. It will not cost you any upkeep this week.");
			}
		}

		if (V.weatherAwareness > 0) {
			if (V.antiWeatherFreeze === 0) {
				div.append(
					`The extreme weather hurts your arcology's ability to function. Reinforcing your passenger terminals increase the weather range at which they can operate.`,
					makePurchase(`Reinforce the passenger terminals`, 50000 * V.upgradeMultiplierArcology, "capEx", {
						notes: [`increases upkeep`],
						handler: () => {
							V.antiWeatherFreeze++;
							V.PC.skill.engineering++;
						}
					}),
				);
			} else if (V.antiWeatherFreeze === 1) {
				div.append("You have reinforced your passenger terminals to function even during bad weather. You can invest in an all-weather transportation system that will remain operational, no matter the weather.");
				div.append(
					makePurchase(`Invest in a heavily-armored transportation system`, 100_000 * V.upgradeMultiplierArcology, "capEx", {
						notes: [`increases upkeep`],
						handler: () => {
							V.antiWeatherFreeze++;
							V.PC.skill.engineering++;
						}
					}),
				);
			} else if (V.antiWeatherFreeze === 2) {
				App.UI.DOM.appendNewElement("div", div, "Your arcology's passenger terminals remain fully operational during even the most extreme weather.");
			}
		} else {
			div.append(`The weather outside the arcology is perfectly manageable, for the time being.`);
		}

		return div;
	}

	function sexualServices() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		const societyClasses = ["lower", "middle", "upper", "top"];

		App.UI.DOM.appendNewElement("h2", div, "Sexual Service Policies");
		App.UI.DOM.appendNewElement("div", div, "If so desired, your assistant can help you manipulate the business environment within your arcology.");
		App.UI.DOM.appendNewElement("div", div, "Breakdown of sexual services supplied by outside parties per societal class.");

		for (const s of societyClasses) {
			const classType = s === "top" ? `millionaires` : `${s} class`;
			App.UI.DOM.appendNewElement("div", div, `${capFirstChar(classType)}: ${V.NPCMarketShare[s + "Class"]/10}%`);
		}
		App.UI.DOM.appendNewElement("div", div);

		for (const s of societyClasses) {
			App.UI.DOM.appendNewElement("div", div, societalView(s, "policies"));
		}

		div.append(rent());

		return div;

		function rent() {
			const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

			const asPercentage = (v) => Math.trunc((v / (V.ACitizens + V.ASlaves)) * 1000) / 10;

			App.UI.DOM.appendNewElement("h2", div, "Population and Rent");
			App.UI.DOM.appendNewElement("div", div, `${arcologyName} is home to the following:`);

			for (const s of societyClasses) {
				App.UI.DOM.appendNewElement("div", div, societalView(s, "rent"));
			}

			App.UI.DOM.appendNewElement("div", div, `Slaves | ${num(V.ASlaves)} | ${asPercentage(V.ASlaves)}%`);

			return div;
		}

		function societalView(s, type) {
			const frag = new DocumentFragment();

			const classType = s === "top" ? "Millionaires" : `${capFirstChar(s)} Class`;
			const calRent = (v) => Math.trunc(V.rent[v] * (1 + (5 - V.baseDifficulty) / 20) / 0.25) / 100;
			const classStr = s + "Class";
			function link(text, type, value, value2 = 0, value3 = 0) {
				return App.UI.DOM.link(`${text}`, () => {
					if (type !== "rent") {
						V[type][classStr] = value;
						if (type === "sexSupplyBarriers") {
							repX(-1000, "subsidiesAndBarriers");
						}
					} else {
						V.rent[classStr] = V.rentDefaults[classStr] * value;
						if (s === "lower") {
							V.rentEffectL = value2;
						} else if (s === "middle") {
							V.rentEffectM = value2;
						} else if (s === "upper") {
							V.rentEffectU = value2;
						} else if (s === "top") {
							V.rentEffectT = value2;
						}
						V.whoreBudget[classStr] *= value3;
					}

					App.UI.reload();
				});
			}

			let choices = [];

			if (type === "policies") {
				if (V.sexSubsidies[classStr] === 0) {
					frag.append(`You can provide a minor subsidy for those selling sexual services to the ${classType}. `);
					choices.push(link(`Minor Subsidy`, "sexSubsidies", 1));
				} else if (V.sexSubsidies[classStr] === 1) {
					frag.append(`You are providing a minor subsidy for those selling sexual services to the ${classType}. `);
					choices.push(link(`Cancel Subsidy`, "sexSubsidies", 0));
					choices.push(link(`Moderate Subsidy`, "sexSubsidies", 2));
				} else if (V.sexSubsidies[classStr] === 2) {
					frag.append(`You are providing a moderate subsidy for those selling sexual services to the ${classType}. `);
					choices.push(link(`Minor Subsidy`, "sexSubsidies", 1));
					choices.push(link(`Substantial Subsidy`, "sexSubsidies", 3));
				} else if (V.sexSubsidies[classStr] === 3) {
					frag.append(`You are providing a substantial subsidy for those selling sexual services to the ${classType}. `);
					choices.push(link(`Moderate Subsidy`, "sexSubsidies", 2));
					choices.push(link(`Gratuitous Subsidy`, "sexSubsidies", 4));
				} else {
					frag.append(`You are providing a gratuitous subsidy for those selling sexual services to the ${classType}. `);
					choices.push(link(`Substantial Subsidy`, "sexSubsidies", 3));
				}

				App.UI.DOM.appendNewElement("span", frag, "Upkeep is relative to the amount provided by other parties. ", ['note']);
				App.UI.DOM.appendNewElement("span", frag, App.UI.DOM.generateLinksStrip(choices));
				App.UI.DOM.appendNewElement("div", frag);

				choices = [];
				if (V.sexSupplyBarriers[classStr] === 0) {
					frag.append(
						`Alternatively administrative "accidents" can happen if you are willing to spend ${num(1000)} reputation and pay a flat upkeep of`,	// TODO: the actual effects of this aren't clear to the player
						App.UI.DOM.makeElement("span", ` ${cashFormat(1000)}. `, ['cash'])
					);
					choices.push(link(`Create Bureaucracy`, "sexSupplyBarriers", 1));
				} else if (V.sexSupplyBarriers[classStr] === 1) {
					frag.append(
						`You have forced some unneeded bureaucracy, making things a little more difficult.
						If you are willing to spend ${num(1000)} reputation you can change this policy.
						Increasing the bureaucracy further will cost a flat upkeep of`,
						App.UI.DOM.makeElement("span", ` ${cashFormat(5000)}. `, ['cash'])
					);
					choices.push(link(`Abolish Bureaucracy`, "sexSupplyBarriers", 0));
					choices.push(link(`Increase Bureaucracy`, "sexSupplyBarriers", 2));
				} else if (V.sexSupplyBarriers[classStr] === 2) {
					frag.append(
						`You have forced considerable bureaucracy, making things a little more difficult.
						If you are willing to spend ${num(1000)} reputation you can change this policy.
						Increasing the bureaucracy further will cost a flat upkeep of`,
						App.UI.DOM.makeElement("span", ` ${cashFormat(20000)}. `, ['cash'])
					);
					choices.push(link(`Reduce Bureaucracy`, "sexSupplyBarriers", 1));
					choices.push(link(`Increase Bureaucracy`, "sexSupplyBarriers", 3));
				} else if (V.sexSupplyBarriers[classStr] === 3) {
					frag.append(
						`You have forced stifling bureaucracy, making things a little more difficult.
						If you are willing to spend ${num(1000)} reputation you can change this policy.
						Increasing the bureaucracy further will cost a flat upkeep of`,
						App.UI.DOM.makeElement("span", ` ${cashFormat(60000)}. `, ['cash'])
					);
					choices.push(link(`Reduce Bureaucracy`, "sexSupplyBarriers", 2));
					choices.push(link(`Increase Bureaucracy`, "sexSupplyBarriers", 4));
				} else {
					frag.append(
						`You have forced suffocating bureaucracy, making things a little more difficult.
						If you are willing to spend ${num(1000)} reputation you can change this policy.`
					);
					choices.push(link(`Reduce Bureaucracy`, "sexSupplyBarriers", 3));
				}
			} else if (type === "rent") {
				const asPercentage = (v) => Math.trunc((v / (V.ACitizens + V.ASlaves)) * 1000) / 10;

				frag.append(
					`${classType} | ${num(V[classStr])} | ${asPercentage(V[classStr])}% | Rent: `,
					App.UI.DOM.makeElement("span", `${cashFormat(calRent(classStr))} `, ['cash'])
				);

				if (V.rent[classStr] > V.rentDefaults[classStr] * 1.5) {
					frag.append(`Very High. `);
					choices.push(link(`Decrease`, "rent", 1.5, 0.94, 9 / 8));
				} else if (V.rent[classStr] > V.rentDefaults[classStr]) {
					frag.append(`High. `);
					choices.push(link(`Increase`, "rent", 2, 0.85, 8 / 9));
					choices.push(link(`Decrease`, "rent", 1, 1, 10 / 9));
				} else if (V.rent[classStr] > V.rentDefaults[classStr] * 0.5) {
					frag.append(`Average. `);
					choices.push(link(`Increase`, "rent", 1.5, 0.94, 9 / 8));
					choices.push(link(`Decrease`, "rent", 0.5, 1.04, 11 / 10));
				} else if (V.rent[classStr] > 0) {
					frag.append(`Low. `);
					choices.push(link(`Increase`, "rent", 1, 1, 10 / 11));
					choices.push(link(`Free Rent`, "rent", 0, 1.1, 12 / 11));
				} else {
					frag.append(`Free. `);
					choices.push(link(`Increase`, "rent", 0.5, 1.04, 11 / 12));
				}
			}

			if (type === "policies" && V.rep > 1000 || type === "rent") {
				App.UI.DOM.appendNewElement("span", frag, App.UI.DOM.generateLinksStrip(choices));
			} else {
				App.UI.DOM.appendNewElement("div", frag, `You are not reputable enough.`);
			}

			return frag;
		}
	}

	function language() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Language");
		div.append(
			`The lingua franca of the arcology is `,
			App.UI.DOM.makeElement("span", `${V.language}.`, ["strong"]),
			App.UI.DOM.makeElement("div", App.UI.DOM.link(`Language options`, () => {
				V.seed = V.language;
			}, [], "Change Language"), ['indent']),
		);

		return div;
	}

	function upgrades() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Special Arcology Upgrades");

		if (V.personalArms === 0 && V.mercenaries === 0 && V.assistant.personality <= 0) {
			div.append(`${arcologyName} has no special upgrades.`);
		} else {
			if (V.personalArms > 0) {
				const text = [];

				text.push(`You own a prototype powered exoskeleton that mounts armor and a smart mortar system, and has rifles mounted into its forearms.`);
				if (V.personalArms > 1) {
					text.push(`Furthermore, your security drones can rearm with small-caliber guns if necessary.`);
				}

				App.UI.DOM.appendNewElement("div", div, text.join(' '));
			}

			if (V.mercenaries > 0) {
				const text = [];

				if (V.mercenaries.isBetween(1, 5)) {
					text.push(`A ${V.mercenaries === 1 ? `squad` : `full platoon`} of mercenaries is permanently quartered in ${arcologyName}.`);
				} else if (V.mercenaries >= 5) {
					text.push(`You have permanently settled a full company of mercenaries in ${arcologyName} as your ${V.mercenariesTitle}.`);
				}

				text.push(`They are grim men and women${V.mercenaries < 5 ? `, heavily armed and armored` : ` who appreciate their luxurious life here and train hard to keep their skills with their prototype armor sharp`}.`);

				App.UI.DOM.appendNewElement("div", div, text.join(' '));
			}
		}

		if (V.assistant.personality > 0) {
			const text = [];

			const {hisA, heA} = getPronouns(assistant.pronouns().main).appendSuffix("A");

			text.push(`${capFirstChar(V.assistant.name)} is using an alternative personality setting, speaking in a sultry, sexual voice, and talking as though the penthouse's sex toys are ${hisA} body.`);

			if (V.assistant.personality > 1) {
				text.push(`${heA} also has charge of all smart piercings in the arcology, and is using ${hisA} adaptations to sexual duties to improve their effectiveness.`);
			}

			App.UI.DOM.appendNewElement("div", div, text.join(' '));
		}

		return div;
	}

	function records() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Records");

		const total = V.oralTotal + V.vaginalTotal + V.analTotal;
		const text = [];

		if (total > 0) {
			text.push(`Your slaves have participated in approximately ${num(total)} sexual encounters: ${num(V.oralTotal)} primarily oral, ${num(V.vaginalTotal)} vanilla, ${num(V.mammaryTotal)} mammary, ${num(V.analTotal)} anal, and ${num(V.penetrativeTotal)} with the slave penetrating another.`);
		} else {
			text.push(`Your slaves haven't had any sexual encounters yet.`);
		}

		if (V.milkTotal > 0 || V.birthsTotal > 0 || (V.cumTotal > 0 && V.seeDicks !== 0)) {
			text.push(`They have produced about ${num(V.milkTotal)} liters of marketable milk, ${V.seeDicks !== 0 ? `about ${num(V.cumTotal)} deciliters of marketable cum,` : ``} and have given birth ${num(V.birthsTotal)} times.`);
		}

		if (V.abortionsTotal > 0 && V.miscarriagesTotal > 0) {
			text.push(`They have had a total of ${num(V.abortionsTotal)} abortions and ${num(V.miscarriagesTotal)} miscarriages.`);
		} else if (V.abortionsTotal > 0) {
			text.push(`They have had a total of ${num(V.abortionsTotal)} abortions.`);
		} else if (V.miscarriagesTotal > 0) {
			text.push(`They have had a total of ${num(V.miscarriagesTotal)} miscarriages.`);
		}
		if (V.fuckdollsSold > 0) { // FIXME: This never increases
			text.push(`${V.fuckdollsSold} mindbroken arcade slaves have been converted into Fuckdolls and sold.`);
		}

		App.UI.DOM.appendNewElement("div", div, text.join(' '));

		if (V.pitFightsTotal > 0 && V.pitKillsTotal > 0) {
			App.UI.DOM.appendNewElement("div", div, `${arcologyName} has hosted ${numberWithPluralOne(V.pitFightsTotal, "pit fight")}, and ${numberWithPluralOne(V.pitKillsTotal, "slave")} slaves ${V.pitKillsTotal === 1 ? `has` : `have`} died in your pit.`);
		} else if (V.pitFightsTotal > 0) {
			App.UI.DOM.appendNewElement("div", div, `${arcologyName} has hosted ${numberWithPluralOne(V.pitFightsTotal, "pit fight")}.`);
		}

		return div;
	}

	function foodMarket() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		if (V.mods.food.enabled && V.mods.food.market) {
			App.UI.DOM.appendNewElement("h2", div, "Food Management");
			div.append(App.UI.foodMarket());
		} else if (V.eventResults.foodCrisis && !V.mods.food.rations) {
			const price = V.PC.skill.trading >= 50 && ["capitalist", "entrepreneur", "business kid"].includes(V.PC.career) || V.PC.skill.trading >= 100 ? 112_500 : 150_000;

			div.append(
				`You can set up the food market for your citizens again, if you'd like.`,
				makePurchase(`Set it up`, price, "capEx", {
					handler: () => {
						V.mods.food.market = true;
						repX(6500, "food");
						App.UI.reload();
					}
				}),
			);
		}

		return div;
	}

	function security() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("h2", div, "Security");

		const cost = 5000 * V.upgradeMultiplierArcology * V.HackingSkillMultiplier;

		if (V.SecExp.buildings.propHub) {
			const innerDiv = document.createElement("div");

			innerDiv.append(`The `, App.UI.DOM.passageLink(`Propaganda Hub`, "propagandaHub"), ` is ready to manipulate reality on your command.`);

			div.append(innerDiv);
		} else {
			App.UI.DOM.appendNewElement("div", div, `Building specialized in the management of authority.`, ["detail"]);
			div.append(makePurchase(`Set up the propaganda hub`, cost, "capEx", {
				notes: [`increases upkeep`],
				handler: App.Mods.SecExp.propHub.init,
			}));
		}

		if (V.SecExp.buildings.secHub) {
			const innerDiv = document.createElement("div");

			innerDiv.append(`The `, App.UI.DOM.passageLink(`security HQ`, "securityHQ"), ` is constantly working to protect your arcology.`);

			div.append(innerDiv);
		} else {
			App.UI.DOM.appendNewElement("div", div, `Building specialized in the management of security and crime.`, ["detail"]);
			div.append(makePurchase(`Set up the security headquarters`, cost, "capEx", {
				notes: [`increases upkeep`],
				handler: App.Mods.SecExp.secHub.init,
			}));
		}

		if (V.SecExp.buildings.barracks) {
			const innerDiv = document.createElement("div");

			innerDiv.append(`The `, App.UI.DOM.passageLink(`barracks`, "secBarracks"), ` patiently await your orders.`);

			div.append(innerDiv);
		} else {
			App.UI.DOM.appendNewElement("div", div, `Building specialized in the management of armed forces.`, ["detail"]);
			div.append(makePurchase(`Set up the barracks`, cost, "capEx", {
				notes: [`increases upkeep`],
				handler: App.Mods.SecExp.barracks.init,
			}));
		}

		if (V.SecExp.buildings.riotCenter && V.SecExp.settings.rebellion.enabled === 1) {
			const innerDiv = document.createElement("div");

			innerDiv.append(`The `, App.UI.DOM.passageLink(`Riot Control Center`, "riotControlCenter"), ` stands ready for action.`);

			div.append(innerDiv);
		} else if (V.SecExp.settings.rebellion.enabled === 1) {
			App.UI.DOM.appendNewElement("div", div, `Building specialized in the management and suppression of rebellions.`, ["detail"]);
			div.append(makePurchase(`Set up the control center`, cost, "capEx", {
				notes: [`increases upkeep`],
				handler: App.Mods.SecExp.riotCenter.init,
			}));
		}

		return div;
	}

	function military() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		const victories = (x) => V.SecExp[x].victories;
		const losses = (x) => V.SecExp[x].losses;
		const count = (x) => victories(x) + losses(x);
		const SF = V.SF.Toggle && V.SF.Active >= 1 ? V.SF.ArmySize : 0;
		const unitsLost = Array.from(App.Mods.SecExp.unit.list().keys()).slice(1).reduce((acc, cur) => acc + V.SecExp.units[cur].dead, 0);

		App.UI.DOM.appendNewElement("h2", div, "Military");

		const text = [];

		text.push(`Your army counts ${num(App.Mods.SecExp.unit.squads("human").reduce((acc, s) => acc + s.troops, 0) + SF)} total soldiers${(V.SF.Toggle && V.SF.Active >= 1) ? ` of which ${num(V.SF.ArmySize)} under the Special Force chain of command and the rest under your direct control` : ``}.`);

		if (V.SecExp.settings.battle.enabled === 1 && count('battles') > 0) {
			text.push(`Your troops were involved in ${num(count('battles'))} battles, of which ${num(V.SecExp.battles.major)} were major engagements. You won`);

			if (count('battles') === victories('battles')) {
				text.push(`all of them.`);
			} else if (count('battles') === losses('battles')) {
				text.push(`none of them.`);
			} else {
				text.push(`${num(victories('battles'))} of them, while the enemy managed to gain the upper hand in the other ${num(losses('battles'))}.`);
			}

			text.push(`You lost a total of ${num(unitsLost)} men, while scoring a total of ${num(V.SecExp.core.totalKills)} kills.`);
		}

		if (V.SecExp.settings.rebellion.enabled === 1 && count('rebellions') > 0) {
			text.push(`Your arcology was involved in ${numberWithPluralOne(count('rebellions'), "rebellion")}${count('rebellions') > 1
				? `. You won ${num(victories('rebellions'))} of them, while the rebels defeated your forces in ${num(losses('rebellions'))}`
				: `, which you ${victories('rebellions') === 1 ? `won` : `lost`}`
			}.`);
		}

		App.UI.DOM.appendNewElement("div", div, text.join(' '));

		return div;
	}

	function events() {
		const div = App.UI.DOM.makeElement("div", null, ['margin-bottom']);

		App.UI.DOM.appendNewElement("div", div, App.UI.DOM.passageLink(`Host Dinner Party`, "Dinner Party Preparations"), ['indent']);

		return div;
	}
};

repo_name: DontAskDontTell/fc

license: mit


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;
		}
	}

	/**
	 * @override
	 * @returns {string}
	 */
	get name() {
		switch (this.type) {
			case 1:
				return "Luxury Apartments";
			case 2:
				return "Apartments";
			case 3:
				return "Dense Apartments";
			default:
				return super.name;
		}
	}

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		return App.Arcology.getCellLinkFromPath(path, this.name);
	}

	/**
	 * @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(containingBuilding) {
		const fragment = document.createDocumentFragment();

		const cost = 10000 * V.upgradeMultiplierArcology;

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

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

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

		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.getCellLinkFromPath = function(path, message) {
	return App.Arcology.getCellLink(message, message, () => V.building.renderCell(path));
};

/**
 * @param {string} linkText
 * @param {string} title
 * @param {function():(HTMLDivElement|DocumentFragment)} content
 * @param {function():void} [callback]
 * @returns {HTMLAnchorElement}
 */
App.Arcology.getCellLink = function(linkText, title, content, callback) {
	return App.UI.DOM.link(linkText, () => {
		if (Dialog.isOpen()) {
			Dialog.close();
		}
		if (callback) {
			callback();
			V.building.refresh();
		}
		Dialog.setup(title);
		$(Dialog.body()).empty().append(content());
		Dialog.open();
	});
};

/**
 * 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: "New"};
	const candidates = App.Arcology.presets.filter(preset => preset.isAllowed(env));
	return candidates.pluck().construct(env).building;
};

/**
 * Determine whether the arcology has a shop of a particular type
 * @param {string} type
 * @returns {boolean}
 */
App.Arcology.hasShopOfType = function(type) {
	return V.building.findCells(cell => (cell instanceof App.Arcology.Cell.Shop) && cell.type === type).length > 0;
};

/**
 * 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]
 * @returns {Node}
 */
App.Arcology.facilityCellContent = function(facility, passageName) {
	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 {DocumentFragment}
	 */
	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 {HTMLDivElement}
	 */
	render() {
		const div = document.createElement("div");
		div.id = "arcology-building-container";
		div.append(this.renderInner());
		return div;
	}

	refresh() {
		App.UI.DOM.replace("#arcology-building-container", this.renderInner());
	}

	/**
	 * @returns {DocumentFragment}
	 */
	renderInner() {
		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 {DocumentFragment}
	 */
	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:
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;
		}
	}

	/**
	 * @override
	 * @returns {string}
	 */
	get name() {
		return this.type;
	}

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

	/**
	 * @param {Array<number>} path
	 * @returns {Node}
	 */
	cellContent(path) {
		switch (this.type) {
			case "Dairy":
				return App.Arcology.facilityCellContent(App.Entity.facilities.dairy);
			case "Farmyard":
				return App.Arcology.facilityCellContent(App.Entity.facilities.farmyard);
			case "Manufacturing":
			case "Pens":
			case "Sweatshops":
				return App.Arcology.getCellLinkFromPath(path, this.type);
			case "Barracks":
				return App.UI.DOM.passageLink("Barracks", "Barracks");
			case "Weapon Manufacturing":
				return App.UI.DOM.passageLink("Weapons Manufacturing", "Weapons Manufacturing");
			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(containingBuilding) {
		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 += `${toSentence(list)}, `;

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

				r += "housed in this sector.";

				if (V.menials > 0 && sweatshopCount() > 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._makeExternalUpgrade(
					`Construct a dairy to milk slaves on an industrial scale`,
					() => {
						V.dairy = 5;
						thisCell.type = "Dairy";
					}, cost, "Dairy", [`will incur upkeep costs`]
				));
			}

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

			if (V.mercenaries) {
				if (V.barracks !== 1) {
					fragment.append(thisCell._makeExternalUpgrade(
						`Build a barracks to properly house your mercenaries`,
						() => {
							V.barracks = 1;
							thisCell.type = "Barracks";
						}, cost, "Barracks", [`will reduce mercenary upkeep`]
					));
				}
			}

			if (V.secExpEnabled > 0 && !V.SecExp.buildings.weapManu) {
				fragment.append(thisCell._makeExternalUpgrade(
					`Convert this sector to weapons manufacturing`,
					() => {
						App.Mods.SecExp.weapManu.Init();
						thisCell.type = "Weapon Manufacturing";
					}, cost, "Weapons Manufacturing", [`will provide a weekly income`]
				));
			}

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

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

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

			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 "transport-hub";
			case "Corporate Market":
				return "corporateMarket";
			default:
				return super.colorClass;
		}
	}

	/**
	 * @override
	 * @returns {string}
	 */
	get name() {
		if (this.type === "Pit") {
			return "Arena";
		}
		return this.type;
	}

	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, "Pit");
			case "Markets":
				return App.Arcology.getCellLinkFromPath(path, "Markets");
			case "Transport Hub":
				return App.UI.DOM.passageLink("Transport Hub", "Transport Hub");
			case "Corporate Market":
				return App.UI.DOM.passageLink(
					"Corporate Market",
					"Market",
					this._prepareCorporateMarket
				);
			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(containingBuilding) {
		const fragment = document.createDocumentFragment();

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

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

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

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

		return fragment;
	}

	/**
	 * @private
	 */
	_prepareCorporateMarket() {
		V.market = new App.Markets.Global("corporate");
		V.nextButton = "Back to Main";
		V.nextLink = "Main";
		V.returnTo = "Main";
	}

	/**
	 * @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
				));
			}
		}

		if (V.verticalizeArcologyLinks !== -1){
			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.capacity > 0) {
				const inc = App.Entity.facilities.incubator;
				const link = App.UI.DOM.passageLink(inc.UIName, "Incubator");
				const desc = `(${numberWithPluralOne(inc.capacity -
					(V.incubator.tanks.length + FetusGlobalReserveCount("incubator")), "empty tank")})`;

				if (V.incubator.readySlaves > 0) {
					wrapper.append(createFacilityDiv(link, App.UI.DOM.combineNodes(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")));
			}
		} else {
			addFacility(fcs.headGirlSuite, "Head Girl Suite");
			addFacility(fcs.armory, "BG Select");
		}

		return fragment;

		/**
		 * @param {ParentNode} outer
		 * @returns {HTMLDivElement}
		 */
		function getWrapper(outer) {
			const wrapper = document.createElement("div");
			if (V.verticalizeArcologyLinks !== 0) {
				if (V.verticalizeArcologyLinks === -1) {
					// use double column for HG suite and Armory.
					let gridClass = `grid${2}`;
					wrapper.classList.add("gridWrapper", gridClass);
				} else {
					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 its 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"; }
};